Basic CmpLog (#113)
* libafl_targets: refactor sancov trace-pc * cmp observer * libaf_targets: new structure to isolate sancov * fix C warning * combined executor * cmp observer and feedback * I2SRandReplace mutator * impl CmpMap for CmpLogMap in libafl_targets * cmplog observer * clippy * TracingStage * working random cmplog mutations * enable cmplog for libfuzzer_stb_image * re-enable new testcase stats print * fix update stats display * bump 0.3.1 * clippy * clippy * no clippy for fuzzers/ * fix Co-authored-by: Dominik Maier <domenukk@gmail.com>
This commit is contained in:
parent
dacfee9be8
commit
acc5ed42a2
@ -6,10 +6,9 @@ cd fuzzers
|
|||||||
|
|
||||||
for fuzzer in *;
|
for fuzzer in *;
|
||||||
do
|
do
|
||||||
echo "[+] Checking fmt, clippy, and building $fuzzer"
|
echo "[+] Checking fmt and building $fuzzer"
|
||||||
cd $fuzzer \
|
cd $fuzzer \
|
||||||
&& cargo fmt --all -- --check \
|
&& cargo fmt --all -- --check \
|
||||||
&& ../../clippy.sh --no-clean \
|
|
||||||
&& cargo build \
|
&& cargo build \
|
||||||
&& cd .. \
|
&& cd .. \
|
||||||
|| exit 1
|
|| exit 1
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "baby_fuzzer"
|
name = "baby_fuzzer"
|
||||||
version = "0.3.0"
|
version = "0.3.1"
|
||||||
authors = ["Andrea Fioraldi <andreafioraldi@gmail.com>", "Dominik Maier <domenukk@gmail.com>"]
|
authors = ["Andrea Fioraldi <andreafioraldi@gmail.com>", "Dominik Maier <domenukk@gmail.com>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "frida_libpng"
|
name = "frida_libpng"
|
||||||
version = "0.3.0"
|
version = "0.3.1"
|
||||||
authors = ["Andrea Fioraldi <andreafioraldi@gmail.com>", "Dominik Maier <domenukk@gmail.com>"]
|
authors = ["Andrea Fioraldi <andreafioraldi@gmail.com>", "Dominik Maier <domenukk@gmail.com>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
build = "build.rs"
|
build = "build.rs"
|
||||||
|
@ -13,7 +13,7 @@ use libafl::{
|
|||||||
os::parse_core_bind_arg,
|
os::parse_core_bind_arg,
|
||||||
rands::StdRand,
|
rands::StdRand,
|
||||||
shmem::{ShMemProvider, StdShMemProvider},
|
shmem::{ShMemProvider, StdShMemProvider},
|
||||||
tuples::tuple_list,
|
tuples::{tuple_list, Merge},
|
||||||
},
|
},
|
||||||
corpus::{
|
corpus::{
|
||||||
ondisk::OnDiskMetadataFormat, Corpus, InMemoryCorpus,
|
ondisk::OnDiskMetadataFormat, Corpus, InMemoryCorpus,
|
||||||
@ -28,7 +28,7 @@ use libafl::{
|
|||||||
fuzzer::{Fuzzer, StdFuzzer},
|
fuzzer::{Fuzzer, StdFuzzer},
|
||||||
inputs::{HasTargetBytes, Input},
|
inputs::{HasTargetBytes, Input},
|
||||||
mutators::{
|
mutators::{
|
||||||
scheduled::{havoc_mutations, StdScheduledMutator},
|
scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator},
|
||||||
token_mutations::Tokens,
|
token_mutations::Tokens,
|
||||||
},
|
},
|
||||||
observers::{HitcountsMapObserver, ObserversTuple, StdMapObserver, TimeObserver},
|
observers::{HitcountsMapObserver, ObserversTuple, StdMapObserver, TimeObserver},
|
||||||
@ -411,7 +411,7 @@ unsafe fn fuzz(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Setup a basic mutator with a mutational stage
|
// Setup a basic mutator with a mutational stage
|
||||||
let mutator = StdScheduledMutator::new(havoc_mutations());
|
let mutator = StdScheduledMutator::new(havoc_mutations().merge(tokens_mutations()));
|
||||||
let mut stages = tuple_list!(StdMutationalStage::new(mutator));
|
let mut stages = tuple_list!(StdMutationalStage::new(mutator));
|
||||||
|
|
||||||
// A minimization+queue policy to get testcasess from the corpus
|
// A minimization+queue policy to get testcasess from the corpus
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "libfuzzer_libmozjpeg"
|
name = "libfuzzer_libmozjpeg"
|
||||||
version = "0.3.0"
|
version = "0.3.1"
|
||||||
authors = ["Andrea Fioraldi <andreafioraldi@gmail.com>", "Dominik Maier <domenukk@gmail.com>"]
|
authors = ["Andrea Fioraldi <andreafioraldi@gmail.com>", "Dominik Maier <domenukk@gmail.com>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
@ -16,7 +16,7 @@ debug = true
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
libafl = { path = "../../libafl/" }
|
libafl = { path = "../../libafl/" }
|
||||||
libafl_targets = { path = "../../libafl_targets/", features = ["pcguard_edges", "value_profile", "libfuzzer"] }
|
libafl_targets = { path = "../../libafl_targets/", features = ["sancov_pcguard_edges", "sancov_value_profile", "libfuzzer"] }
|
||||||
# TODO Include it only when building cc
|
# TODO Include it only when building cc
|
||||||
libafl_cc = { path = "../../libafl_cc/" }
|
libafl_cc = { path = "../../libafl_cc/" }
|
||||||
|
|
||||||
|
@ -4,14 +4,18 @@
|
|||||||
use std::{env, path::PathBuf};
|
use std::{env, path::PathBuf};
|
||||||
|
|
||||||
use libafl::{
|
use libafl::{
|
||||||
bolts::{current_nanos, rands::StdRand, tuples::tuple_list},
|
bolts::{
|
||||||
|
current_nanos,
|
||||||
|
rands::StdRand,
|
||||||
|
tuples::{tuple_list, Merge},
|
||||||
|
},
|
||||||
corpus::{Corpus, InMemoryCorpus, OnDiskCorpus, RandCorpusScheduler},
|
corpus::{Corpus, InMemoryCorpus, OnDiskCorpus, RandCorpusScheduler},
|
||||||
events::setup_restarting_mgr_std,
|
events::setup_restarting_mgr_std,
|
||||||
executors::{inprocess::InProcessExecutor, ExitKind},
|
executors::{inprocess::InProcessExecutor, ExitKind},
|
||||||
feedback_or,
|
feedback_or,
|
||||||
feedbacks::{CrashFeedback, MapFeedbackState, MaxMapFeedback},
|
feedbacks::{CrashFeedback, MapFeedbackState, MaxMapFeedback},
|
||||||
fuzzer::{Fuzzer, StdFuzzer},
|
fuzzer::{Fuzzer, StdFuzzer},
|
||||||
mutators::scheduled::{havoc_mutations, StdScheduledMutator},
|
mutators::scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator},
|
||||||
mutators::token_mutations::Tokens,
|
mutators::token_mutations::Tokens,
|
||||||
observers::StdMapObserver,
|
observers::StdMapObserver,
|
||||||
stages::mutational::StdMutationalStage,
|
stages::mutational::StdMutationalStage,
|
||||||
@ -114,7 +118,7 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Setup a basic mutator with a mutational stage
|
// Setup a basic mutator with a mutational stage
|
||||||
let mutator = StdScheduledMutator::new(havoc_mutations());
|
let mutator = StdScheduledMutator::new(havoc_mutations().merge(tokens_mutations()));
|
||||||
let mut stages = tuple_list!(StdMutationalStage::new(mutator));
|
let mut stages = tuple_list!(StdMutationalStage::new(mutator));
|
||||||
|
|
||||||
// A random policy to get testcasess from the corpus
|
// A random policy to get testcasess from the corpus
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "libfuzzer_libpng"
|
name = "libfuzzer_libpng"
|
||||||
version = "0.3.0"
|
version = "0.3.1"
|
||||||
authors = ["Andrea Fioraldi <andreafioraldi@gmail.com>", "Dominik Maier <domenukk@gmail.com>"]
|
authors = ["Andrea Fioraldi <andreafioraldi@gmail.com>", "Dominik Maier <domenukk@gmail.com>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
@ -22,7 +22,7 @@ num_cpus = "1.0"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
libafl = { path = "../../libafl/", features = ["default", "introspection"] }
|
libafl = { path = "../../libafl/", features = ["default", "introspection"] }
|
||||||
# libafl = { path = "../../libafl/", features = ["default"] }
|
# libafl = { path = "../../libafl/", features = ["default"] }
|
||||||
libafl_targets = { path = "../../libafl_targets/", features = ["pcguard_hitcounts", "libfuzzer"] }
|
libafl_targets = { path = "../../libafl_targets/", features = ["sancov_pcguard_hitcounts", "libfuzzer"] }
|
||||||
# TODO Include it only when building cc
|
# TODO Include it only when building cc
|
||||||
libafl_cc = { path = "../../libafl_cc/" }
|
libafl_cc = { path = "../../libafl_cc/" }
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ use core::time::Duration;
|
|||||||
use std::{env, path::PathBuf};
|
use std::{env, path::PathBuf};
|
||||||
|
|
||||||
use libafl::{
|
use libafl::{
|
||||||
bolts::tuples::tuple_list,
|
bolts::tuples::{tuple_list, Merge},
|
||||||
bolts::{current_nanos, rands::StdRand},
|
bolts::{current_nanos, rands::StdRand},
|
||||||
corpus::{
|
corpus::{
|
||||||
Corpus, InMemoryCorpus, IndexesLenTimeMinimizerCorpusScheduler, OnDiskCorpus,
|
Corpus, InMemoryCorpus, IndexesLenTimeMinimizerCorpusScheduler, OnDiskCorpus,
|
||||||
@ -16,7 +16,7 @@ use libafl::{
|
|||||||
feedback_or,
|
feedback_or,
|
||||||
feedbacks::{CrashFeedback, MapFeedbackState, MaxMapFeedback, TimeFeedback, TimeoutFeedback},
|
feedbacks::{CrashFeedback, MapFeedbackState, MaxMapFeedback, TimeFeedback, TimeoutFeedback},
|
||||||
fuzzer::{Fuzzer, StdFuzzer},
|
fuzzer::{Fuzzer, StdFuzzer},
|
||||||
mutators::scheduled::{havoc_mutations, StdScheduledMutator},
|
mutators::scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator},
|
||||||
mutators::token_mutations::Tokens,
|
mutators::token_mutations::Tokens,
|
||||||
observers::{HitcountsMapObserver, StdMapObserver, TimeObserver},
|
observers::{HitcountsMapObserver, StdMapObserver, TimeObserver},
|
||||||
stages::mutational::StdMutationalStage,
|
stages::mutational::StdMutationalStage,
|
||||||
@ -116,7 +116,7 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Setup a basic mutator with a mutational stage
|
// Setup a basic mutator with a mutational stage
|
||||||
let mutator = StdScheduledMutator::new(havoc_mutations());
|
let mutator = StdScheduledMutator::new(havoc_mutations().merge(tokens_mutations()));
|
||||||
let mut stages = tuple_list!(StdMutationalStage::new(mutator));
|
let mut stages = tuple_list!(StdMutationalStage::new(mutator));
|
||||||
|
|
||||||
// A minimization+queue policy to get testcasess from the corpus
|
// A minimization+queue policy to get testcasess from the corpus
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "libfuzzer_libpng_launcher"
|
name = "libfuzzer_libpng_launcher"
|
||||||
version = "0.3.0"
|
version = "0.3.1"
|
||||||
authors = ["Andrea Fioraldi <andreafioraldi@gmail.com>", "Dominik Maier <domenukk@gmail.com>"]
|
authors = ["Andrea Fioraldi <andreafioraldi@gmail.com>", "Dominik Maier <domenukk@gmail.com>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
@ -21,7 +21,7 @@ num_cpus = "1.0"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
libafl = { path = "../../libafl/" }
|
libafl = { path = "../../libafl/" }
|
||||||
libafl_targets = { path = "../../libafl_targets/", features = ["pcguard_hitcounts", "libfuzzer"] }
|
libafl_targets = { path = "../../libafl_targets/", features = ["sancov_pcguard_hitcounts", "libfuzzer"] }
|
||||||
# TODO Include it only when building cc
|
# TODO Include it only when building cc
|
||||||
libafl_cc = { path = "../../libafl_cc/" }
|
libafl_cc = { path = "../../libafl_cc/" }
|
||||||
clap = { version = "3.0.0-beta.2", features = ["yaml"] }
|
clap = { version = "3.0.0-beta.2", features = ["yaml"] }
|
||||||
|
@ -14,7 +14,7 @@ use libafl::{
|
|||||||
os::parse_core_bind_arg,
|
os::parse_core_bind_arg,
|
||||||
rands::StdRand,
|
rands::StdRand,
|
||||||
shmem::{ShMemProvider, StdShMemProvider},
|
shmem::{ShMemProvider, StdShMemProvider},
|
||||||
tuples::tuple_list,
|
tuples::{tuple_list, Merge},
|
||||||
},
|
},
|
||||||
corpus::{
|
corpus::{
|
||||||
Corpus, InMemoryCorpus, IndexesLenTimeMinimizerCorpusScheduler, OnDiskCorpus,
|
Corpus, InMemoryCorpus, IndexesLenTimeMinimizerCorpusScheduler, OnDiskCorpus,
|
||||||
@ -24,7 +24,7 @@ use libafl::{
|
|||||||
feedback_or,
|
feedback_or,
|
||||||
feedbacks::{CrashFeedback, MapFeedbackState, MaxMapFeedback, TimeFeedback, TimeoutFeedback},
|
feedbacks::{CrashFeedback, MapFeedbackState, MaxMapFeedback, TimeFeedback, TimeoutFeedback},
|
||||||
fuzzer::{Fuzzer, StdFuzzer},
|
fuzzer::{Fuzzer, StdFuzzer},
|
||||||
mutators::scheduled::{havoc_mutations, StdScheduledMutator},
|
mutators::scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator},
|
||||||
mutators::token_mutations::Tokens,
|
mutators::token_mutations::Tokens,
|
||||||
observers::{HitcountsMapObserver, StdMapObserver, TimeObserver},
|
observers::{HitcountsMapObserver, StdMapObserver, TimeObserver},
|
||||||
stages::mutational::StdMutationalStage,
|
stages::mutational::StdMutationalStage,
|
||||||
@ -117,7 +117,7 @@ pub fn main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Setup a basic mutator with a mutational stage
|
// Setup a basic mutator with a mutational stage
|
||||||
let mutator = StdScheduledMutator::new(havoc_mutations());
|
let mutator = StdScheduledMutator::new(havoc_mutations().merge(tokens_mutations()));
|
||||||
let mut stages = tuple_list!(StdMutationalStage::new(mutator));
|
let mut stages = tuple_list!(StdMutationalStage::new(mutator));
|
||||||
|
|
||||||
// A minimization+queue policy to get testcasess from the corpus
|
// A minimization+queue policy to get testcasess from the corpus
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "libfuzzer_reachability"
|
name = "libfuzzer_reachability"
|
||||||
version = "0.3.0"
|
version = "0.3.1"
|
||||||
authors = ["Andrea Fioraldi <andreafioraldi@gmail.com>", "Dominik Maier <domenukk@gmail.com>"]
|
authors = ["Andrea Fioraldi <andreafioraldi@gmail.com>", "Dominik Maier <domenukk@gmail.com>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
@ -21,7 +21,7 @@ num_cpus = "1.0"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
libafl = { path = "../../libafl/" }
|
libafl = { path = "../../libafl/" }
|
||||||
libafl_targets = { path = "../../libafl_targets/", features = ["pcguard_hitcounts", "libfuzzer"] }
|
libafl_targets = { path = "../../libafl_targets/", features = ["sancov_pcguard_hitcounts", "libfuzzer"] }
|
||||||
# TODO Include it only when building cc
|
# TODO Include it only when building cc
|
||||||
libafl_cc = { path = "../../libafl_cc/" }
|
libafl_cc = { path = "../../libafl_cc/" }
|
||||||
|
|
||||||
|
@ -11,10 +11,9 @@ use libafl::{
|
|||||||
feedbacks::{MapFeedbackState, MaxMapFeedback, ReachabilityFeedback},
|
feedbacks::{MapFeedbackState, MaxMapFeedback, ReachabilityFeedback},
|
||||||
fuzzer::{Fuzzer, StdFuzzer},
|
fuzzer::{Fuzzer, StdFuzzer},
|
||||||
mutators::scheduled::{havoc_mutations, StdScheduledMutator},
|
mutators::scheduled::{havoc_mutations, StdScheduledMutator},
|
||||||
mutators::token_mutations::Tokens,
|
|
||||||
observers::{HitcountsMapObserver, StdMapObserver},
|
observers::{HitcountsMapObserver, StdMapObserver},
|
||||||
stages::mutational::StdMutationalStage,
|
stages::mutational::StdMutationalStage,
|
||||||
state::{HasCorpus, HasMetadata, StdState},
|
state::{HasCorpus, StdState},
|
||||||
stats::SimpleStats,
|
stats::SimpleStats,
|
||||||
Error,
|
Error,
|
||||||
};
|
};
|
||||||
@ -97,17 +96,6 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
|
|||||||
|
|
||||||
println!("We're a client, let's fuzz :)");
|
println!("We're a client, let's fuzz :)");
|
||||||
|
|
||||||
// Create a PNG dictionary if not existing
|
|
||||||
if state.metadata().get::<Tokens>().is_none() {
|
|
||||||
state.add_metadata(Tokens::new(vec![
|
|
||||||
vec![137, 80, 78, 71, 13, 10, 26, 10], // PNG header
|
|
||||||
"IHDR".as_bytes().to_vec(),
|
|
||||||
"IDAT".as_bytes().to_vec(),
|
|
||||||
"PLTE".as_bytes().to_vec(),
|
|
||||||
"IEND".as_bytes().to_vec(),
|
|
||||||
]));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Setup a basic mutator with a mutational stage
|
// Setup a basic mutator with a mutational stage
|
||||||
let mutator = StdScheduledMutator::new(havoc_mutations());
|
let mutator = StdScheduledMutator::new(havoc_mutations());
|
||||||
let mut stages = tuple_list!(StdMutationalStage::new(mutator));
|
let mut stages = tuple_list!(StdMutationalStage::new(mutator));
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "libfuzzer_stb_image"
|
name = "libfuzzer_stb_image"
|
||||||
version = "0.3.0"
|
version = "0.3.1"
|
||||||
authors = ["Andrea Fioraldi <andreafioraldi@gmail.com>", "Dominik Maier <domenukk@gmail.com>"]
|
authors = ["Andrea Fioraldi <andreafioraldi@gmail.com>", "Dominik Maier <domenukk@gmail.com>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
build = "build.rs"
|
build = "build.rs"
|
||||||
@ -17,7 +17,7 @@ debug = true
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
libafl = { path = "../../libafl/" }
|
libafl = { path = "../../libafl/" }
|
||||||
libafl_targets = { path = "../../libafl_targets/", features = ["pcguard_edges", "libfuzzer"] }
|
libafl_targets = { path = "../../libafl_targets/", features = ["sancov_pcguard_edges", "sancov_cmplog", "libfuzzer"] }
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
cc = { version = "1.0", features = ["parallel"] }
|
cc = { version = "1.0", features = ["parallel"] }
|
||||||
|
@ -14,7 +14,7 @@ fn main() {
|
|||||||
|
|
||||||
cc::Build::new()
|
cc::Build::new()
|
||||||
// Use sanitizer coverage to track the edges in the PUT
|
// Use sanitizer coverage to track the edges in the PUT
|
||||||
.flag("-fsanitize-coverage=trace-pc-guard")
|
.flag("-fsanitize-coverage=trace-pc-guard,trace-cmp")
|
||||||
// Take advantage of LTO (needs lld-link set in your cargo config)
|
// Take advantage of LTO (needs lld-link set in your cargo config)
|
||||||
//.flag("-flto=thin")
|
//.flag("-flto=thin")
|
||||||
.flag("-Wno-sign-compare")
|
.flag("-Wno-sign-compare")
|
||||||
|
@ -15,15 +15,18 @@ use libafl::{
|
|||||||
feedbacks::{CrashFeedback, MapFeedbackState, MaxMapFeedback, TimeFeedback},
|
feedbacks::{CrashFeedback, MapFeedbackState, MaxMapFeedback, TimeFeedback},
|
||||||
fuzzer::{Fuzzer, StdFuzzer},
|
fuzzer::{Fuzzer, StdFuzzer},
|
||||||
mutators::scheduled::{havoc_mutations, StdScheduledMutator},
|
mutators::scheduled::{havoc_mutations, StdScheduledMutator},
|
||||||
mutators::token_mutations::Tokens,
|
mutators::token_mutations::I2SRandReplace,
|
||||||
observers::{StdMapObserver, TimeObserver},
|
observers::{StdMapObserver, TimeObserver},
|
||||||
stages::mutational::StdMutationalStage,
|
stages::{StdMutationalStage, TracingStage},
|
||||||
state::{HasCorpus, HasMetadata, StdState},
|
state::{HasCorpus, StdState},
|
||||||
stats::SimpleStats,
|
stats::SimpleStats,
|
||||||
Error,
|
Error,
|
||||||
};
|
};
|
||||||
|
|
||||||
use libafl_targets::{libfuzzer_initialize, libfuzzer_test_one_input, EDGES_MAP, MAX_EDGES_NUM};
|
use libafl_targets::{
|
||||||
|
libfuzzer_initialize, libfuzzer_test_one_input, CmpLogObserver, CMPLOG_MAP, EDGES_MAP,
|
||||||
|
MAX_EDGES_NUM,
|
||||||
|
};
|
||||||
|
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
// Registry the metadata types used in this fuzzer
|
// Registry the metadata types used in this fuzzer
|
||||||
@ -68,6 +71,9 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
|
|||||||
// Create an observation channel to keep track of the execution time
|
// Create an observation channel to keep track of the execution time
|
||||||
let time_observer = TimeObserver::new("time");
|
let time_observer = TimeObserver::new("time");
|
||||||
|
|
||||||
|
let cmplog = unsafe { &mut CMPLOG_MAP };
|
||||||
|
let cmplog_observer = CmpLogObserver::new("cmplog", cmplog, true);
|
||||||
|
|
||||||
// The state of the edges feedback.
|
// The state of the edges feedback.
|
||||||
let feedback_state = MapFeedbackState::with_observer(&edges_observer);
|
let feedback_state = MapFeedbackState::with_observer(&edges_observer);
|
||||||
|
|
||||||
@ -101,21 +107,6 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
|
|||||||
|
|
||||||
println!("We're a client, let's fuzz :)");
|
println!("We're a client, let's fuzz :)");
|
||||||
|
|
||||||
// Create a PNG dictionary if not existing
|
|
||||||
if state.metadata().get::<Tokens>().is_none() {
|
|
||||||
state.add_metadata(Tokens::new(vec![
|
|
||||||
vec![137, 80, 78, 71, 13, 10, 26, 10], // PNG header
|
|
||||||
"IHDR".as_bytes().to_vec(),
|
|
||||||
"IDAT".as_bytes().to_vec(),
|
|
||||||
"PLTE".as_bytes().to_vec(),
|
|
||||||
"IEND".as_bytes().to_vec(),
|
|
||||||
]));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Setup a basic mutator with a mutational stage
|
|
||||||
let mutator = StdScheduledMutator::new(havoc_mutations());
|
|
||||||
let mut stages = tuple_list!(StdMutationalStage::new(mutator));
|
|
||||||
|
|
||||||
// A minimization+queue policy to get testcasess from the corpus
|
// A minimization+queue policy to get testcasess from the corpus
|
||||||
let scheduler = IndexesLenTimeMinimizerCorpusScheduler::new(QueueCorpusScheduler::new());
|
let scheduler = IndexesLenTimeMinimizerCorpusScheduler::new(QueueCorpusScheduler::new());
|
||||||
|
|
||||||
@ -157,6 +148,31 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
|
|||||||
println!("We imported {} inputs from disk.", state.corpus().count());
|
println!("We imported {} inputs from disk.", state.corpus().count());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Secondary harness due to mut ownership
|
||||||
|
let mut harness = |buf: &[u8]| {
|
||||||
|
libfuzzer_test_one_input(buf);
|
||||||
|
ExitKind::Ok
|
||||||
|
};
|
||||||
|
|
||||||
|
// Setup a tracing stage in which we log comparisons
|
||||||
|
let tracing = TracingStage::new(InProcessExecutor::new(
|
||||||
|
&mut harness,
|
||||||
|
tuple_list!(cmplog_observer),
|
||||||
|
&mut fuzzer,
|
||||||
|
&mut state,
|
||||||
|
&mut restarting_mgr,
|
||||||
|
)?);
|
||||||
|
|
||||||
|
// Setup a randomic Input2State stage
|
||||||
|
let i2s = StdMutationalStage::new(StdScheduledMutator::new(tuple_list!(I2SRandReplace::new())));
|
||||||
|
|
||||||
|
// Setup a basic mutator
|
||||||
|
let mutator = StdScheduledMutator::new(havoc_mutations());
|
||||||
|
let mutational = StdMutationalStage::new(mutator);
|
||||||
|
|
||||||
|
// The order of the stages matter!
|
||||||
|
let mut stages = tuple_list!(tracing, i2s, mutational);
|
||||||
|
|
||||||
fuzzer.fuzz_loop(&mut stages, &mut executor, &mut state, &mut restarting_mgr)?;
|
fuzzer.fuzz_loop(&mut stages, &mut executor, &mut state, &mut restarting_mgr)?;
|
||||||
|
|
||||||
// Never reached
|
// Never reached
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "libafl"
|
name = "libafl"
|
||||||
version = "0.3.0"
|
version = "0.3.1"
|
||||||
authors = ["Andrea Fioraldi <andreafioraldi@gmail.com>", "Dominik Maier <domenukk@gmail.com>"]
|
authors = ["Andrea Fioraldi <andreafioraldi@gmail.com>", "Dominik Maier <domenukk@gmail.com>"]
|
||||||
description = "Slot your own fuzzers together and extend their features using Rust"
|
description = "Slot your own fuzzers together and extend their features using Rust"
|
||||||
documentation = "https://docs.rs/libafl"
|
documentation = "https://docs.rs/libafl"
|
||||||
@ -52,7 +52,7 @@ path = "./examples/llmp_test/main.rs"
|
|||||||
required-features = ["std"]
|
required-features = ["std"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
libafl_derive = { optional = true, path = "../libafl_derive", version = "0.3.0" }
|
libafl_derive = { optional = true, path = "../libafl_derive", version = "0.3.1" }
|
||||||
tuple_list = "0.1.2"
|
tuple_list = "0.1.2"
|
||||||
hashbrown = { version = "0.9", features = ["serde", "ahash-compile-time-rng"] } # A faster hashmap, nostd compatible
|
hashbrown = { version = "0.9", features = ["serde", "ahash-compile-time-rng"] } # A faster hashmap, nostd compatible
|
||||||
num = "0.4.0"
|
num = "0.4.0"
|
||||||
|
@ -308,10 +308,10 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Allows prepending of values to a tuple
|
/// Allows prepending of values to a tuple
|
||||||
pub trait Prepend<T>: TupleList {
|
pub trait Prepend<T> {
|
||||||
/// The Resulting [`TupleList`], of an [`Prepend::prepend()`] call,
|
/// The Resulting [`TupleList`], of an [`Prepend::prepend()`] call,
|
||||||
/// including the prepended entry.
|
/// including the prepended entry.
|
||||||
type PreprendResult: TupleList;
|
type PreprendResult;
|
||||||
|
|
||||||
/// Prepend a value to this tuple, returning a new tuple with prepended value.
|
/// Prepend a value to this tuple, returning a new tuple with prepended value.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
@ -319,10 +319,7 @@ pub trait Prepend<T>: TupleList {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Implement prepend for tuple list.
|
/// Implement prepend for tuple list.
|
||||||
impl<Tail, T> Prepend<T> for Tail
|
impl<Tail, T> Prepend<T> for Tail {
|
||||||
where
|
|
||||||
Tail: TupleList,
|
|
||||||
{
|
|
||||||
type PreprendResult = Self;
|
type PreprendResult = Self;
|
||||||
|
|
||||||
fn prepend(self, value: T) -> (T, Self::PreprendResult) {
|
fn prepend(self, value: T) -> (T, Self::PreprendResult) {
|
||||||
@ -330,11 +327,11 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Append to a `TupeList`
|
/// Append to a tuple
|
||||||
pub trait Append<T>: TupleList {
|
pub trait Append<T> {
|
||||||
/// The Resulting [`TupleList`], of an [`Append::append()`] call,
|
/// The Resulting [`TupleList`], of an [`Append::append()`] call,
|
||||||
/// including the appended entry.
|
/// including the appended entry.
|
||||||
type AppendResult: TupleList;
|
type AppendResult;
|
||||||
|
|
||||||
/// Append Value and return the tuple
|
/// Append Value and return the tuple
|
||||||
#[must_use]
|
#[must_use]
|
||||||
@ -353,9 +350,7 @@ impl<T> Append<T> for () {
|
|||||||
/// Implement append for non-empty tuple list.
|
/// Implement append for non-empty tuple list.
|
||||||
impl<Head, Tail, T> Append<T> for (Head, Tail)
|
impl<Head, Tail, T> Append<T> for (Head, Tail)
|
||||||
where
|
where
|
||||||
Self: TupleList,
|
|
||||||
Tail: Append<T>,
|
Tail: Append<T>,
|
||||||
(Head, Tail::AppendResult): TupleList,
|
|
||||||
{
|
{
|
||||||
type AppendResult = (Head, Tail::AppendResult);
|
type AppendResult = (Head, Tail::AppendResult);
|
||||||
|
|
||||||
@ -365,6 +360,38 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Merge two `TupeList`
|
||||||
|
pub trait Merge<T> {
|
||||||
|
/// The Resulting [`TupleList`], of an [`Merge::merge()`] call
|
||||||
|
type MergeResult;
|
||||||
|
|
||||||
|
/// Merge and return the merged tuple
|
||||||
|
#[must_use]
|
||||||
|
fn merge(self, value: T) -> Self::MergeResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Implement merge for an empty tuple list.
|
||||||
|
impl<T> Merge<T> for () {
|
||||||
|
type MergeResult = T;
|
||||||
|
|
||||||
|
fn merge(self, value: T) -> Self::MergeResult {
|
||||||
|
value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Implement merge for non-empty tuple list.
|
||||||
|
impl<Head, Tail, T> Merge<T> for (Head, Tail)
|
||||||
|
where
|
||||||
|
Tail: Merge<T>,
|
||||||
|
{
|
||||||
|
type MergeResult = (Head, Tail::MergeResult);
|
||||||
|
|
||||||
|
fn merge(self, value: T) -> Self::MergeResult {
|
||||||
|
let (head, tail) = self;
|
||||||
|
(head, tail.merge(value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Iterate over a tuple, executing the given `expr` for each element.
|
/// Iterate over a tuple, executing the given `expr` for each element.
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! tuple_for_each {
|
macro_rules! tuple_for_each {
|
||||||
|
@ -249,7 +249,7 @@ where
|
|||||||
let client = stats.client_stats_mut_for(sender_id);
|
let client = stats.client_stats_mut_for(sender_id);
|
||||||
client.update_corpus_size(*corpus_size as u64);
|
client.update_corpus_size(*corpus_size as u64);
|
||||||
client.update_executions(*executions as u64, *time);
|
client.update_executions(*executions as u64, *time);
|
||||||
// stats.display(event.name().to_string() + " #" + &sender_id.to_string());
|
stats.display(event.name().to_string() + " #" + &sender_id.to_string());
|
||||||
Ok(BrokerEventResult::Forward)
|
Ok(BrokerEventResult::Forward)
|
||||||
}
|
}
|
||||||
Event::UpdateStats {
|
Event::UpdateStats {
|
||||||
@ -260,9 +260,7 @@ where
|
|||||||
// TODO: The stats buffer should be added on client add.
|
// TODO: The stats buffer should be added on client add.
|
||||||
let client = stats.client_stats_mut_for(sender_id);
|
let client = stats.client_stats_mut_for(sender_id);
|
||||||
client.update_executions(*executions as u64, *time);
|
client.update_executions(*executions as u64, *time);
|
||||||
if sender_id == 1 {
|
stats.display(event.name().to_string() + " #" + &sender_id.to_string());
|
||||||
stats.display(event.name().to_string() + " #" + &sender_id.to_string());
|
|
||||||
}
|
|
||||||
Ok(BrokerEventResult::Handled)
|
Ok(BrokerEventResult::Handled)
|
||||||
}
|
}
|
||||||
#[cfg(feature = "introspection")]
|
#[cfg(feature = "introspection")]
|
||||||
|
117
libafl/src/executors/combined.rs
Normal file
117
libafl/src/executors/combined.rs
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
//! A `CombinedExecutor` wraps a primary executor and a secondary one
|
||||||
|
|
||||||
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
executors::{
|
||||||
|
Executor, ExitKind, HasExecHooks, HasExecHooksTuple, HasObservers, HasObserversHooks,
|
||||||
|
},
|
||||||
|
inputs::Input,
|
||||||
|
observers::ObserversTuple,
|
||||||
|
Error,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// A [`CombinedExecutor`] wraps a primary executor, forwarding its methods, and a secondary one
|
||||||
|
pub struct CombinedExecutor<A, B, I>
|
||||||
|
where
|
||||||
|
A: Executor<I>,
|
||||||
|
B: Executor<I>,
|
||||||
|
I: Input,
|
||||||
|
{
|
||||||
|
primary: A,
|
||||||
|
secondary: B,
|
||||||
|
phantom: PhantomData<I>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A, B, I> CombinedExecutor<A, B, I>
|
||||||
|
where
|
||||||
|
A: Executor<I>,
|
||||||
|
B: Executor<I>,
|
||||||
|
I: Input,
|
||||||
|
{
|
||||||
|
/// Create a new `CombinedExecutor`, wrapping the given `executor`s.
|
||||||
|
pub fn new(primary: A, secondary: B) -> Self {
|
||||||
|
Self {
|
||||||
|
primary,
|
||||||
|
secondary,
|
||||||
|
phantom: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Retrieve the primary `Executor` that is wrapped by this `CombinedExecutor`.
|
||||||
|
pub fn primary(&mut self) -> &mut A {
|
||||||
|
&mut self.primary
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Retrieve the secondary `Executor` that is wrapped by this `CombinedExecutor`.
|
||||||
|
pub fn secondary(&mut self) -> &mut B {
|
||||||
|
&mut self.secondary
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A, B, I> Executor<I> for CombinedExecutor<A, B, I>
|
||||||
|
where
|
||||||
|
A: Executor<I>,
|
||||||
|
B: Executor<I>,
|
||||||
|
I: Input,
|
||||||
|
{
|
||||||
|
fn run_target(&mut self, input: &I) -> Result<ExitKind, Error> {
|
||||||
|
self.primary.run_target(input)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A, B, I, OT> HasObservers<OT> for CombinedExecutor<A, B, I>
|
||||||
|
where
|
||||||
|
A: Executor<I> + HasObservers<OT>,
|
||||||
|
B: Executor<I>,
|
||||||
|
I: Input,
|
||||||
|
OT: ObserversTuple,
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
fn observers(&self) -> &OT {
|
||||||
|
self.primary.observers()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn observers_mut(&mut self) -> &mut OT {
|
||||||
|
self.primary.observers_mut()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A, B, EM, I, OT, S, Z> HasObserversHooks<EM, I, OT, S, Z> for CombinedExecutor<A, B, I>
|
||||||
|
where
|
||||||
|
A: Executor<I> + HasObservers<OT>,
|
||||||
|
B: Executor<I>,
|
||||||
|
I: Input,
|
||||||
|
OT: ObserversTuple + HasExecHooksTuple<EM, I, S, Z>,
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A, B, EM, I, S, Z> HasExecHooks<EM, I, S, Z> for CombinedExecutor<A, B, I>
|
||||||
|
where
|
||||||
|
A: Executor<I> + HasExecHooks<EM, I, S, Z>,
|
||||||
|
B: Executor<I>,
|
||||||
|
I: Input,
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
fn pre_exec(
|
||||||
|
&mut self,
|
||||||
|
fuzzer: &mut Z,
|
||||||
|
state: &mut S,
|
||||||
|
mgr: &mut EM,
|
||||||
|
input: &I,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
self.primary.pre_exec(fuzzer, state, mgr, input)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn post_exec(
|
||||||
|
&mut self,
|
||||||
|
fuzzer: &mut Z,
|
||||||
|
state: &mut S,
|
||||||
|
mgr: &mut EM,
|
||||||
|
input: &I,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
self.primary.post_exec(fuzzer, state, mgr, input)
|
||||||
|
}
|
||||||
|
}
|
@ -4,6 +4,8 @@ pub mod inprocess;
|
|||||||
pub use inprocess::InProcessExecutor;
|
pub use inprocess::InProcessExecutor;
|
||||||
pub mod timeout;
|
pub mod timeout;
|
||||||
pub use timeout::TimeoutExecutor;
|
pub use timeout::TimeoutExecutor;
|
||||||
|
pub mod combined;
|
||||||
|
pub use combined::CombinedExecutor;
|
||||||
|
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ use serde::{Deserialize, Serialize};
|
|||||||
use crate::{
|
use crate::{
|
||||||
bolts::{
|
bolts::{
|
||||||
rands::Rand,
|
rands::Rand,
|
||||||
tuples::{tuple_list, NamedTuple},
|
tuples::{tuple_list, tuple_list_type, NamedTuple},
|
||||||
AsSlice,
|
AsSlice,
|
||||||
},
|
},
|
||||||
corpus::Corpus,
|
corpus::Corpus,
|
||||||
@ -198,7 +198,34 @@ where
|
|||||||
|
|
||||||
/// Get the mutations that compose the Havoc mutator
|
/// Get the mutations that compose the Havoc mutator
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn havoc_mutations<C, I, R, S>() -> impl MutatorsTuple<I, S>
|
pub fn havoc_mutations<C, I, R, S>() -> tuple_list_type!(
|
||||||
|
BitFlipMutator<I, R, S>,
|
||||||
|
ByteFlipMutator<I, R, S>,
|
||||||
|
ByteIncMutator<I, R, S>,
|
||||||
|
ByteDecMutator<I, R, S>,
|
||||||
|
ByteNegMutator<I, R, S>,
|
||||||
|
ByteRandMutator<I, R, S>,
|
||||||
|
ByteAddMutator<I, R, S>,
|
||||||
|
WordAddMutator<I, R, S>,
|
||||||
|
DwordAddMutator<I, R, S>,
|
||||||
|
QwordAddMutator<I, R, S>,
|
||||||
|
ByteInterestingMutator<I, R, S>,
|
||||||
|
WordInterestingMutator<I, R, S>,
|
||||||
|
DwordInterestingMutator<I, R, S>,
|
||||||
|
BytesDeleteMutator<I, R, S>,
|
||||||
|
BytesDeleteMutator<I, R, S>,
|
||||||
|
BytesDeleteMutator<I, R, S>,
|
||||||
|
BytesDeleteMutator<I, R, S>,
|
||||||
|
BytesExpandMutator<I, R, S>,
|
||||||
|
BytesInsertMutator<I, R, S>,
|
||||||
|
BytesRandInsertMutator<I, R, S>,
|
||||||
|
BytesSetMutator<I, R, S>,
|
||||||
|
BytesRandSetMutator<I, R, S>,
|
||||||
|
BytesCopyMutator<I, R, S>,
|
||||||
|
BytesSwapMutator<I, R, S>,
|
||||||
|
CrossoverInsertMutator<C, I, R, S>,
|
||||||
|
CrossoverReplaceMutator<C, I, R, S>,
|
||||||
|
)
|
||||||
where
|
where
|
||||||
I: Input + HasBytesVec,
|
I: Input + HasBytesVec,
|
||||||
S: HasRand<R> + HasCorpus<C, I> + HasMetadata + HasMaxSize,
|
S: HasRand<R> + HasCorpus<C, I> + HasMetadata + HasMaxSize,
|
||||||
@ -230,13 +257,24 @@ where
|
|||||||
BytesRandSetMutator::new(),
|
BytesRandSetMutator::new(),
|
||||||
BytesCopyMutator::new(),
|
BytesCopyMutator::new(),
|
||||||
BytesSwapMutator::new(),
|
BytesSwapMutator::new(),
|
||||||
TokenInsert::new(),
|
|
||||||
TokenReplace::new(),
|
|
||||||
CrossoverInsertMutator::new(),
|
CrossoverInsertMutator::new(),
|
||||||
CrossoverReplaceMutator::new(),
|
CrossoverReplaceMutator::new(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the mutations that uses the Tokens metadata
|
||||||
|
#[must_use]
|
||||||
|
pub fn tokens_mutations<C, I, R, S>(
|
||||||
|
) -> tuple_list_type!(TokenInsert<I, R, S>, TokenReplace<I, R, S>)
|
||||||
|
where
|
||||||
|
I: Input + HasBytesVec,
|
||||||
|
S: HasRand<R> + HasCorpus<C, I> + HasMetadata + HasMaxSize,
|
||||||
|
C: Corpus<I>,
|
||||||
|
R: Rand,
|
||||||
|
{
|
||||||
|
tuple_list!(TokenInsert::new(), TokenReplace::new(),)
|
||||||
|
}
|
||||||
|
|
||||||
/// A logging [`Mutator`] that wraps around a [`StdScheduledMutator`].
|
/// A logging [`Mutator`] that wraps around a [`StdScheduledMutator`].
|
||||||
pub struct LoggerScheduledMutator<C, I, MT, R, S, SM>
|
pub struct LoggerScheduledMutator<C, I, MT, R, S, SM>
|
||||||
where
|
where
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
//! Tokens are what afl calls extras or dictionaries.
|
//! Tokens are what afl calls extras or dictionaries.
|
||||||
//! They may be inserted as part of mutations during fuzzing.
|
//! They may be inserted as part of mutations during fuzzing.
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
use core::marker::PhantomData;
|
use core::{convert::TryInto, marker::PhantomData, mem::size_of};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
@ -17,6 +17,7 @@ use crate::{
|
|||||||
bolts::rands::Rand,
|
bolts::rands::Rand,
|
||||||
inputs::{HasBytesVec, Input},
|
inputs::{HasBytesVec, Input},
|
||||||
mutators::{buffer_self_copy, mutations::buffer_copy, MutationResult, Mutator, Named},
|
mutators::{buffer_self_copy, mutations::buffer_copy, MutationResult, Mutator, Named},
|
||||||
|
observers::cmp::{CmpValues, CmpValuesMetadata},
|
||||||
state::{HasMaxSize, HasMetadata, HasRand},
|
state::{HasMaxSize, HasMetadata, HasRand},
|
||||||
Error,
|
Error,
|
||||||
};
|
};
|
||||||
@ -291,6 +292,195 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A `I2SRandReplace` [`Mutator`] replaces a random matching input-2-state comparison operand with the other.
|
||||||
|
/// it needs a valid [`CmpValuesMetadata`] in the state.
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct I2SRandReplace<I, R, S>
|
||||||
|
where
|
||||||
|
I: Input + HasBytesVec,
|
||||||
|
S: HasMetadata + HasRand<R> + HasMaxSize,
|
||||||
|
R: Rand,
|
||||||
|
{
|
||||||
|
phantom: PhantomData<(I, R, S)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I, R, S> Mutator<I, S> for I2SRandReplace<I, R, S>
|
||||||
|
where
|
||||||
|
I: Input + HasBytesVec,
|
||||||
|
S: HasMetadata + HasRand<R> + HasMaxSize,
|
||||||
|
R: Rand,
|
||||||
|
{
|
||||||
|
#[allow(clippy::too_many_lines)]
|
||||||
|
fn mutate(
|
||||||
|
&mut self,
|
||||||
|
state: &mut S,
|
||||||
|
input: &mut I,
|
||||||
|
_stage_idx: i32,
|
||||||
|
) -> Result<MutationResult, Error> {
|
||||||
|
let size = input.bytes().len();
|
||||||
|
if size == 0 {
|
||||||
|
return Ok(MutationResult::Skipped);
|
||||||
|
}
|
||||||
|
|
||||||
|
let cmps_len = {
|
||||||
|
let meta = state.metadata().get::<CmpValuesMetadata>();
|
||||||
|
if meta.is_none() {
|
||||||
|
return Ok(MutationResult::Skipped);
|
||||||
|
}
|
||||||
|
if meta.unwrap().list.is_empty() {
|
||||||
|
return Ok(MutationResult::Skipped);
|
||||||
|
}
|
||||||
|
meta.unwrap().list.len()
|
||||||
|
};
|
||||||
|
let idx = state.rand_mut().below(cmps_len as u64) as usize;
|
||||||
|
|
||||||
|
let off = state.rand_mut().below(size as u64) as usize;
|
||||||
|
let len = input.bytes().len();
|
||||||
|
let bytes = input.bytes_mut();
|
||||||
|
|
||||||
|
let meta = state.metadata().get::<CmpValuesMetadata>().unwrap();
|
||||||
|
let cmp_values = &meta.list[idx];
|
||||||
|
|
||||||
|
let mut result = MutationResult::Skipped;
|
||||||
|
match cmp_values {
|
||||||
|
CmpValues::U8(v) => {
|
||||||
|
for byte in bytes.iter_mut().take(len).skip(off) {
|
||||||
|
if *byte == v.0 {
|
||||||
|
*byte = v.1;
|
||||||
|
result = MutationResult::Mutated;
|
||||||
|
break;
|
||||||
|
} else if *byte == v.1 {
|
||||||
|
*byte = v.0;
|
||||||
|
result = MutationResult::Mutated;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CmpValues::U16(v) => {
|
||||||
|
if len >= size_of::<u16>() {
|
||||||
|
for i in off..len - (size_of::<u16>() - 1) {
|
||||||
|
let val =
|
||||||
|
u16::from_ne_bytes(bytes[i..i + size_of::<u16>()].try_into().unwrap());
|
||||||
|
if val == v.0 {
|
||||||
|
let new_bytes = v.1.to_ne_bytes();
|
||||||
|
bytes[i..i + size_of::<u16>()].copy_from_slice(&new_bytes);
|
||||||
|
result = MutationResult::Mutated;
|
||||||
|
break;
|
||||||
|
} else if val.swap_bytes() == v.0 {
|
||||||
|
let new_bytes = v.1.swap_bytes().to_ne_bytes();
|
||||||
|
bytes[i..i + size_of::<u16>()].copy_from_slice(&new_bytes);
|
||||||
|
result = MutationResult::Mutated;
|
||||||
|
break;
|
||||||
|
} else if val == v.1 {
|
||||||
|
let new_bytes = v.0.to_ne_bytes();
|
||||||
|
bytes[i..i + size_of::<u16>()].copy_from_slice(&new_bytes);
|
||||||
|
result = MutationResult::Mutated;
|
||||||
|
break;
|
||||||
|
} else if val.swap_bytes() == v.1 {
|
||||||
|
let new_bytes = v.0.swap_bytes().to_ne_bytes();
|
||||||
|
bytes[i..i + size_of::<u16>()].copy_from_slice(&new_bytes);
|
||||||
|
result = MutationResult::Mutated;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CmpValues::U32(v) => {
|
||||||
|
if len >= size_of::<u32>() {
|
||||||
|
for i in off..len - (size_of::<u32>() - 1) {
|
||||||
|
let val =
|
||||||
|
u32::from_ne_bytes(bytes[i..i + size_of::<u32>()].try_into().unwrap());
|
||||||
|
if val == v.0 {
|
||||||
|
let new_bytes = v.1.to_ne_bytes();
|
||||||
|
bytes[i..i + size_of::<u32>()].copy_from_slice(&new_bytes);
|
||||||
|
result = MutationResult::Mutated;
|
||||||
|
break;
|
||||||
|
} else if val.swap_bytes() == v.0 {
|
||||||
|
let new_bytes = v.1.swap_bytes().to_ne_bytes();
|
||||||
|
bytes[i..i + size_of::<u32>()].copy_from_slice(&new_bytes);
|
||||||
|
result = MutationResult::Mutated;
|
||||||
|
break;
|
||||||
|
} else if val == v.1 {
|
||||||
|
let new_bytes = v.0.to_ne_bytes();
|
||||||
|
bytes[i..i + size_of::<u32>()].copy_from_slice(&new_bytes);
|
||||||
|
result = MutationResult::Mutated;
|
||||||
|
break;
|
||||||
|
} else if val.swap_bytes() == v.1 {
|
||||||
|
let new_bytes = v.0.swap_bytes().to_ne_bytes();
|
||||||
|
bytes[i..i + size_of::<u32>()].copy_from_slice(&new_bytes);
|
||||||
|
result = MutationResult::Mutated;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CmpValues::U64(v) => {
|
||||||
|
if len >= size_of::<u64>() {
|
||||||
|
for i in off..len - (size_of::<u64>() - 1) {
|
||||||
|
let val =
|
||||||
|
u64::from_ne_bytes(bytes[i..i + size_of::<u64>()].try_into().unwrap());
|
||||||
|
if val == v.0 {
|
||||||
|
let new_bytes = v.1.to_ne_bytes();
|
||||||
|
bytes[i..i + size_of::<u64>()].copy_from_slice(&new_bytes);
|
||||||
|
result = MutationResult::Mutated;
|
||||||
|
break;
|
||||||
|
} else if val.swap_bytes() == v.0 {
|
||||||
|
let new_bytes = v.1.swap_bytes().to_ne_bytes();
|
||||||
|
bytes[i..i + size_of::<u64>()].copy_from_slice(&new_bytes);
|
||||||
|
result = MutationResult::Mutated;
|
||||||
|
break;
|
||||||
|
} else if val == v.1 {
|
||||||
|
let new_bytes = v.0.to_ne_bytes();
|
||||||
|
bytes[i..i + size_of::<u64>()].copy_from_slice(&new_bytes);
|
||||||
|
result = MutationResult::Mutated;
|
||||||
|
break;
|
||||||
|
} else if val.swap_bytes() == v.1 {
|
||||||
|
let new_bytes = v.0.swap_bytes().to_ne_bytes();
|
||||||
|
bytes[i..i + size_of::<u64>()].copy_from_slice(&new_bytes);
|
||||||
|
result = MutationResult::Mutated;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CmpValues::Bytes(_v) => {
|
||||||
|
// TODO
|
||||||
|
// buffer_copy(input.bytes_mut(), token, 0, off, len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//println!("{:?}", result);
|
||||||
|
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I, R, S> Named for I2SRandReplace<I, R, S>
|
||||||
|
where
|
||||||
|
I: Input + HasBytesVec,
|
||||||
|
S: HasMetadata + HasRand<R> + HasMaxSize,
|
||||||
|
R: Rand,
|
||||||
|
{
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"I2SRandReplace"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I, R, S> I2SRandReplace<I, R, S>
|
||||||
|
where
|
||||||
|
I: Input + HasBytesVec,
|
||||||
|
S: HasMetadata + HasRand<R> + HasMaxSize,
|
||||||
|
R: Rand,
|
||||||
|
{
|
||||||
|
/// Creates a new `I2SRandReplace` struct.
|
||||||
|
#[must_use]
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
phantom: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
|
254
libafl/src/observers/cmp.rs
Normal file
254
libafl/src/observers/cmp.rs
Normal file
@ -0,0 +1,254 @@
|
|||||||
|
//! The `CmpObserver` provides access to the logged values of CMP instructions
|
||||||
|
|
||||||
|
use alloc::{
|
||||||
|
string::{String, ToString},
|
||||||
|
vec::Vec,
|
||||||
|
};
|
||||||
|
use serde::{de::DeserializeOwned, Deserialize, Serialize};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
bolts::{ownedref::OwnedRefMut, tuples::Named, AsSlice},
|
||||||
|
executors::HasExecHooks,
|
||||||
|
observers::Observer,
|
||||||
|
state::HasMetadata,
|
||||||
|
Error,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
pub enum CmpValues {
|
||||||
|
U8((u8, u8)),
|
||||||
|
U16((u16, u16)),
|
||||||
|
U32((u32, u32)),
|
||||||
|
U64((u64, u64)),
|
||||||
|
Bytes((Vec<u8>, Vec<u8>)),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CmpValues {
|
||||||
|
#[must_use]
|
||||||
|
pub fn is_numeric(&self) -> bool {
|
||||||
|
matches!(
|
||||||
|
self,
|
||||||
|
CmpValues::U8(_) | CmpValues::U16(_) | CmpValues::U32(_) | CmpValues::U64(_)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn to_u64_tuple(&self) -> Option<(u64, u64)> {
|
||||||
|
match self {
|
||||||
|
CmpValues::U8(t) => Some((u64::from(t.0), u64::from(t.1))),
|
||||||
|
CmpValues::U16(t) => Some((u64::from(t.0), u64::from(t.1))),
|
||||||
|
CmpValues::U32(t) => Some((u64::from(t.0), u64::from(t.1))),
|
||||||
|
CmpValues::U64(t) => Some(*t),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A state metadata holding a list of values logged from comparisons
|
||||||
|
#[derive(Default, Serialize, Deserialize)]
|
||||||
|
pub struct CmpValuesMetadata {
|
||||||
|
/// A `list` of values.
|
||||||
|
pub list: Vec<CmpValues>,
|
||||||
|
}
|
||||||
|
|
||||||
|
crate::impl_serdeany!(CmpValuesMetadata);
|
||||||
|
|
||||||
|
impl AsSlice<CmpValues> for CmpValuesMetadata {
|
||||||
|
/// Convert to a slice
|
||||||
|
#[must_use]
|
||||||
|
fn as_slice(&self) -> &[CmpValues] {
|
||||||
|
self.list.as_slice()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CmpValuesMetadata {
|
||||||
|
/// Creates a new [`struct@CmpValuesMetadata`]
|
||||||
|
#[must_use]
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self { list: vec![] }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A [`CmpMap`] traces comparisons during the current execution
|
||||||
|
pub trait CmpMap: Serialize + DeserializeOwned {
|
||||||
|
/// Get the number of cmps
|
||||||
|
fn len(&self) -> usize;
|
||||||
|
|
||||||
|
/// Get if it is empty
|
||||||
|
#[must_use]
|
||||||
|
fn is_empty(&self) -> bool {
|
||||||
|
self.len() == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the number of executions for a cmp
|
||||||
|
fn executions_for(&self, idx: usize) -> usize;
|
||||||
|
|
||||||
|
// Get the number of logged executions for a cmp
|
||||||
|
fn usable_executions_for(&self, idx: usize) -> usize;
|
||||||
|
|
||||||
|
// Get the logged values for a cmp
|
||||||
|
fn values_of(&self, idx: usize, execution: usize) -> CmpValues;
|
||||||
|
|
||||||
|
/// Reset the state
|
||||||
|
fn reset(&mut self) -> Result<(), Error>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A [`CmpObserver`] observes the traced comparisons during the current execution using a [`CmpMap`]
|
||||||
|
pub trait CmpObserver<CM>: Observer
|
||||||
|
where
|
||||||
|
CM: CmpMap,
|
||||||
|
{
|
||||||
|
/// Get the number of usable cmps (all by default)
|
||||||
|
fn usable_count(&self) -> usize;
|
||||||
|
|
||||||
|
/// Get the `CmpMap`
|
||||||
|
fn map(&self) -> &CM;
|
||||||
|
|
||||||
|
/// Get the `CmpMap` (mut)
|
||||||
|
fn map_mut(&mut self) -> &mut CM;
|
||||||
|
|
||||||
|
/// Add [`CmpValuesMetadata`] to the State including the logged values.
|
||||||
|
/// This routine does a basic loop filtering because loop index cmps are not interesting.
|
||||||
|
fn add_cmpvalues_meta<S>(&mut self, state: &mut S)
|
||||||
|
where
|
||||||
|
S: HasMetadata,
|
||||||
|
{
|
||||||
|
if state.metadata().get::<CmpValuesMetadata>().is_none() {
|
||||||
|
state.add_metadata(CmpValuesMetadata::new());
|
||||||
|
}
|
||||||
|
let meta = state.metadata_mut().get_mut::<CmpValuesMetadata>().unwrap();
|
||||||
|
meta.list.clear();
|
||||||
|
let count = self.usable_count();
|
||||||
|
for i in 0..count {
|
||||||
|
let execs = self.map().usable_executions_for(i);
|
||||||
|
if execs > 0 {
|
||||||
|
// Recongize loops and discard if needed
|
||||||
|
if execs > 4 {
|
||||||
|
let mut increasing_v0 = 0;
|
||||||
|
let mut increasing_v1 = 0;
|
||||||
|
let mut decreasing_v0 = 0;
|
||||||
|
let mut decreasing_v1 = 0;
|
||||||
|
|
||||||
|
let mut last: Option<CmpValues> = None;
|
||||||
|
for j in 0..execs {
|
||||||
|
let val = self.map().values_of(i, j);
|
||||||
|
if let Some(l) = last.and_then(|x| x.to_u64_tuple()) {
|
||||||
|
if let Some(v) = val.to_u64_tuple() {
|
||||||
|
if l.0.wrapping_add(1) == v.0 {
|
||||||
|
increasing_v0 += 1;
|
||||||
|
}
|
||||||
|
if l.1.wrapping_add(1) == v.1 {
|
||||||
|
increasing_v1 += 1;
|
||||||
|
}
|
||||||
|
if l.0.wrapping_sub(1) == v.0 {
|
||||||
|
decreasing_v0 += 1;
|
||||||
|
}
|
||||||
|
if l.1.wrapping_sub(1) == v.1 {
|
||||||
|
decreasing_v1 += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
last = Some(val);
|
||||||
|
}
|
||||||
|
// We check for execs-2 because the logged execs may wrap and have something like
|
||||||
|
// 8 9 10 3 4 5 6 7
|
||||||
|
if increasing_v0 >= execs - 2
|
||||||
|
|| increasing_v1 >= execs - 2
|
||||||
|
|| decreasing_v0 >= execs - 2
|
||||||
|
|| decreasing_v1 >= execs - 2
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for j in 0..execs {
|
||||||
|
meta.list.push(self.map().values_of(i, j));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A standard [`CmpObserver`] observer
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
#[serde(bound = "CM: serde::de::DeserializeOwned")]
|
||||||
|
pub struct StdCmpObserver<'a, CM>
|
||||||
|
where
|
||||||
|
CM: CmpMap,
|
||||||
|
{
|
||||||
|
map: OwnedRefMut<'a, CM>,
|
||||||
|
size: Option<OwnedRefMut<'a, usize>>,
|
||||||
|
name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, CM> CmpObserver<CM> for StdCmpObserver<'a, CM>
|
||||||
|
where
|
||||||
|
CM: CmpMap,
|
||||||
|
{
|
||||||
|
/// Get the number of usable cmps (all by default)
|
||||||
|
fn usable_count(&self) -> usize {
|
||||||
|
match &self.size {
|
||||||
|
None => self.map().len(),
|
||||||
|
Some(o) => *o.as_ref(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn map(&self) -> &CM {
|
||||||
|
self.map.as_ref()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn map_mut(&mut self) -> &mut CM {
|
||||||
|
self.map.as_mut()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, CM> Observer for StdCmpObserver<'a, CM> where CM: CmpMap {}
|
||||||
|
|
||||||
|
impl<'a, CM, EM, I, S, Z> HasExecHooks<EM, I, S, Z> for StdCmpObserver<'a, CM>
|
||||||
|
where
|
||||||
|
CM: CmpMap,
|
||||||
|
{
|
||||||
|
fn pre_exec(
|
||||||
|
&mut self,
|
||||||
|
_fuzzer: &mut Z,
|
||||||
|
_state: &mut S,
|
||||||
|
_mgr: &mut EM,
|
||||||
|
_input: &I,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
self.map.as_mut().reset()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, CM> Named for StdCmpObserver<'a, CM>
|
||||||
|
where
|
||||||
|
CM: CmpMap,
|
||||||
|
{
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
&self.name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, CM> StdCmpObserver<'a, CM>
|
||||||
|
where
|
||||||
|
CM: CmpMap,
|
||||||
|
{
|
||||||
|
/// Creates a new [`StdCmpObserver`] with the given name and map.
|
||||||
|
#[must_use]
|
||||||
|
pub fn new(name: &'static str, map: &'a mut CM) -> Self {
|
||||||
|
Self {
|
||||||
|
name: name.to_string(),
|
||||||
|
size: None,
|
||||||
|
map: OwnedRefMut::Ref(map),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new [`StdCmpObserver`] with the given name, map and reference to variable size.
|
||||||
|
#[must_use]
|
||||||
|
pub fn with_size(name: &'static str, map: &'a mut CM, size: &'a mut usize) -> Self {
|
||||||
|
Self {
|
||||||
|
name: name.to_string(),
|
||||||
|
size: Some(OwnedRefMut::Ref(size)),
|
||||||
|
map: OwnedRefMut::Ref(map),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -3,6 +3,9 @@
|
|||||||
pub mod map;
|
pub mod map;
|
||||||
pub use map::*;
|
pub use map::*;
|
||||||
|
|
||||||
|
pub mod cmp;
|
||||||
|
pub use cmp::*;
|
||||||
|
|
||||||
use alloc::string::{String, ToString};
|
use alloc::string::{String, ToString};
|
||||||
use core::time::Duration;
|
use core::time::Duration;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
@ -6,9 +6,11 @@ Other stages may enrich [`crate::corpus::Testcase`]s with metadata.
|
|||||||
|
|
||||||
/// Mutational stage is the normal fuzzing stage,
|
/// Mutational stage is the normal fuzzing stage,
|
||||||
pub mod mutational;
|
pub mod mutational;
|
||||||
|
|
||||||
pub use mutational::{MutationalStage, StdMutationalStage};
|
pub use mutational::{MutationalStage, StdMutationalStage};
|
||||||
|
|
||||||
|
pub mod tracing;
|
||||||
|
pub use tracing::TracingStage;
|
||||||
|
|
||||||
//pub mod power;
|
//pub mod power;
|
||||||
//pub use power::PowerMutationalStage;
|
//pub use power::PowerMutationalStage;
|
||||||
use crate::Error;
|
use crate::Error;
|
||||||
|
113
libafl/src/stages/tracing.rs
Normal file
113
libafl/src/stages/tracing.rs
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
use core::{marker::PhantomData, mem::drop};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
corpus::Corpus,
|
||||||
|
executors::{Executor, HasExecHooks, HasExecHooksTuple, HasObservers, HasObserversHooks},
|
||||||
|
inputs::Input,
|
||||||
|
mark_feature_time,
|
||||||
|
observers::ObserversTuple,
|
||||||
|
stages::Stage,
|
||||||
|
start_timer,
|
||||||
|
state::{HasClientPerfStats, HasCorpus, HasExecutions},
|
||||||
|
Error,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[cfg(feature = "introspection")]
|
||||||
|
use crate::stats::PerfFeature;
|
||||||
|
|
||||||
|
/// The default mutational stage
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct TracingStage<C, EM, I, OT, S, TE, Z>
|
||||||
|
where
|
||||||
|
I: Input,
|
||||||
|
C: Corpus<I>,
|
||||||
|
TE: Executor<I>
|
||||||
|
+ HasObservers<OT>
|
||||||
|
+ HasExecHooks<EM, I, S, Z>
|
||||||
|
+ HasObserversHooks<EM, I, OT, S, Z>,
|
||||||
|
OT: ObserversTuple + HasExecHooksTuple<EM, I, S, Z>,
|
||||||
|
S: HasClientPerfStats + HasExecutions + HasCorpus<C, I>,
|
||||||
|
{
|
||||||
|
tracer_executor: TE,
|
||||||
|
#[allow(clippy::type_complexity)]
|
||||||
|
phantom: PhantomData<(C, EM, I, OT, S, TE, Z)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E, C, EM, I, OT, S, TE, Z> Stage<E, EM, S, Z> for TracingStage<C, EM, I, OT, S, TE, Z>
|
||||||
|
where
|
||||||
|
I: Input,
|
||||||
|
C: Corpus<I>,
|
||||||
|
TE: Executor<I>
|
||||||
|
+ HasObservers<OT>
|
||||||
|
+ HasExecHooks<EM, I, S, Z>
|
||||||
|
+ HasObserversHooks<EM, I, OT, S, Z>,
|
||||||
|
OT: ObserversTuple + HasExecHooksTuple<EM, I, S, Z>,
|
||||||
|
S: HasClientPerfStats + HasExecutions + HasCorpus<C, I>,
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
fn perform(
|
||||||
|
&mut self,
|
||||||
|
fuzzer: &mut Z,
|
||||||
|
_executor: &mut E,
|
||||||
|
state: &mut S,
|
||||||
|
manager: &mut EM,
|
||||||
|
corpus_idx: usize,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
start_timer!(state);
|
||||||
|
let input = state
|
||||||
|
.corpus()
|
||||||
|
.get(corpus_idx)?
|
||||||
|
.borrow_mut()
|
||||||
|
.load_input()?
|
||||||
|
.clone();
|
||||||
|
mark_feature_time!(state, PerfFeature::GetInputFromCorpus);
|
||||||
|
|
||||||
|
start_timer!(state);
|
||||||
|
self.tracer_executor
|
||||||
|
.pre_exec_observers(fuzzer, state, manager, &input)?;
|
||||||
|
mark_feature_time!(state, PerfFeature::PreExecObservers);
|
||||||
|
|
||||||
|
start_timer!(state);
|
||||||
|
self.tracer_executor
|
||||||
|
.pre_exec(fuzzer, state, manager, &input)?;
|
||||||
|
mark_feature_time!(state, PerfFeature::PreExec);
|
||||||
|
|
||||||
|
start_timer!(state);
|
||||||
|
drop(self.tracer_executor.run_target(&input)?);
|
||||||
|
mark_feature_time!(state, PerfFeature::TargetExecution);
|
||||||
|
|
||||||
|
start_timer!(state);
|
||||||
|
self.tracer_executor
|
||||||
|
.post_exec(fuzzer, state, manager, &input)?;
|
||||||
|
mark_feature_time!(state, PerfFeature::PostExec);
|
||||||
|
|
||||||
|
*state.executions_mut() += 1;
|
||||||
|
|
||||||
|
start_timer!(state);
|
||||||
|
self.tracer_executor
|
||||||
|
.post_exec_observers(fuzzer, state, manager, &input)?;
|
||||||
|
mark_feature_time!(state, PerfFeature::PostExecObservers);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<C, EM, I, OT, S, TE, Z> TracingStage<C, EM, I, OT, S, TE, Z>
|
||||||
|
where
|
||||||
|
I: Input,
|
||||||
|
C: Corpus<I>,
|
||||||
|
TE: Executor<I>
|
||||||
|
+ HasObservers<OT>
|
||||||
|
+ HasExecHooks<EM, I, S, Z>
|
||||||
|
+ HasObserversHooks<EM, I, OT, S, Z>,
|
||||||
|
OT: ObserversTuple + HasExecHooksTuple<EM, I, S, Z>,
|
||||||
|
S: HasClientPerfStats + HasExecutions + HasCorpus<C, I>,
|
||||||
|
{
|
||||||
|
/// Creates a new default mutational stage
|
||||||
|
pub fn new(tracer_executor: TE) -> Self {
|
||||||
|
Self {
|
||||||
|
tracer_executor,
|
||||||
|
phantom: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "libafl_cc"
|
name = "libafl_cc"
|
||||||
version = "0.3.0"
|
version = "0.3.1"
|
||||||
authors = ["Andrea Fioraldi <andreafioraldi@gmail.com>"]
|
authors = ["Andrea Fioraldi <andreafioraldi@gmail.com>"]
|
||||||
description = "Commodity library to wrap compilers and link LibAFL"
|
description = "Commodity library to wrap compilers and link LibAFL"
|
||||||
documentation = "https://docs.rs/libafl_cc"
|
documentation = "https://docs.rs/libafl_cc"
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "libafl_derive"
|
name = "libafl_derive"
|
||||||
version = "0.3.0"
|
version = "0.3.1"
|
||||||
authors = ["Andrea Fioraldi <andreafioraldi@gmail.com>"]
|
authors = ["Andrea Fioraldi <andreafioraldi@gmail.com>"]
|
||||||
description = "Derive proc-macro crate for LibAFL"
|
description = "Derive proc-macro crate for LibAFL"
|
||||||
documentation = "https://docs.rs/libafl_derive"
|
documentation = "https://docs.rs/libafl_derive"
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "libafl_frida"
|
name = "libafl_frida"
|
||||||
version = "0.3.0"
|
version = "0.3.1"
|
||||||
authors = ["s1341 <github@shmarya.net>"]
|
authors = ["s1341 <github@shmarya.net>"]
|
||||||
description = "Frida backend library for LibAFL"
|
description = "Frida backend library for LibAFL"
|
||||||
documentation = "https://docs.rs/libafl_frida"
|
documentation = "https://docs.rs/libafl_frida"
|
||||||
@ -14,8 +14,8 @@ edition = "2018"
|
|||||||
cc = { version = "1.0", features = ["parallel"] }
|
cc = { version = "1.0", features = ["parallel"] }
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
libafl = { path = "../libafl", version = "0.3.0", features = ["std", "libafl_derive"] }
|
libafl = { path = "../libafl", version = "0.3.1", features = ["std", "libafl_derive"] }
|
||||||
libafl_targets = { path = "../libafl_targets", version = "0.3.0" }
|
libafl_targets = { path = "../libafl_targets", version = "0.3.1" }
|
||||||
nix = "0.20.0"
|
nix = "0.20.0"
|
||||||
libc = "0.2.92"
|
libc = "0.2.92"
|
||||||
hashbrown = "0.11"
|
hashbrown = "0.11"
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "libafl_targets"
|
name = "libafl_targets"
|
||||||
version = "0.3.0"
|
version = "0.3.1"
|
||||||
authors = ["Andrea Fioraldi <andreafioraldi@gmail.com>"]
|
authors = ["Andrea Fioraldi <andreafioraldi@gmail.com>"]
|
||||||
description = "Common code for target instrumentation that can be used combined with LibAFL"
|
description = "Common code for target instrumentation that can be used combined with LibAFL"
|
||||||
documentation = "https://docs.rs/libafl_targets"
|
documentation = "https://docs.rs/libafl_targets"
|
||||||
@ -12,12 +12,12 @@ edition = "2018"
|
|||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = []
|
default = []
|
||||||
pcguard_edges = []
|
|
||||||
pcguard_hitcounts = []
|
|
||||||
libfuzzer = []
|
libfuzzer = []
|
||||||
value_profile = []
|
sancov_pcguard_edges = []
|
||||||
cmplog = []
|
sancov_pcguard_hitcounts = []
|
||||||
pcguard = ["pcguard_hitcounts"]
|
sancov_value_profile = []
|
||||||
|
sancov_cmplog = []
|
||||||
|
sancov_pcguard = ["sancov_pcguard_hitcounts"]
|
||||||
clippy = [] # Ignore compiler warnings during clippy
|
clippy = [] # Ignore compiler warnings during clippy
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
@ -25,3 +25,6 @@ cc = { version = "1.0", features = ["parallel"] }
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
rangemap = "0.1.10"
|
rangemap = "0.1.10"
|
||||||
|
libafl = { path = "../libafl", version = "0.3", features = [] }
|
||||||
|
serde = { version = "1.0", default-features = false, features = ["alloc"] } # serialization lib
|
||||||
|
serde-big-array = "0.3.2"
|
||||||
|
@ -12,6 +12,23 @@ fn main() {
|
|||||||
//std::env::set_var("CC", "clang");
|
//std::env::set_var("CC", "clang");
|
||||||
//std::env::set_var("CXX", "clang++");
|
//std::env::set_var("CXX", "clang++");
|
||||||
|
|
||||||
|
#[cfg(any(feature = "sancov_value_profile", feature = "sancov_cmplog"))]
|
||||||
|
{
|
||||||
|
println!("cargo:rerun-if-changed=src/sancov_cmp.c");
|
||||||
|
|
||||||
|
let mut sancov_cmp = cc::Build::new();
|
||||||
|
|
||||||
|
#[cfg(feature = "sancov_value_profile")]
|
||||||
|
sancov_cmp.define("SANCOV_VALUE_PROFILE", "1");
|
||||||
|
|
||||||
|
#[cfg(feature = "sancov_cmplog")]
|
||||||
|
sancov_cmp.define("SANCOV_CMPLOG", "1");
|
||||||
|
|
||||||
|
sancov_cmp
|
||||||
|
.file(_src_dir.join("sancov_cmp.c"))
|
||||||
|
.compile("sancov_cmp");
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "libfuzzer")]
|
#[cfg(feature = "libfuzzer")]
|
||||||
{
|
{
|
||||||
println!("cargo:rerun-if-changed=src/libfuzzer_compatibility.c");
|
println!("cargo:rerun-if-changed=src/libfuzzer_compatibility.c");
|
||||||
@ -21,24 +38,6 @@ fn main() {
|
|||||||
.compile("libfuzzer_compatibility");
|
.compile("libfuzzer_compatibility");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "value_profile")]
|
|
||||||
{
|
|
||||||
println!("cargo:rerun-if-changed=src/value_profile.c");
|
|
||||||
|
|
||||||
cc::Build::new()
|
|
||||||
.file(_src_dir.join("value_profile.c"))
|
|
||||||
.compile("value_profile");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "cmplog")]
|
|
||||||
{
|
|
||||||
println!("cargo:rerun-if-changed=src/cmplog.c");
|
|
||||||
|
|
||||||
cc::Build::new()
|
|
||||||
.file(_src_dir.join("cmplog.c"))
|
|
||||||
.compile("cmplog");
|
|
||||||
}
|
|
||||||
|
|
||||||
println!("cargo:rustc-link-search=native={}", &out_dir);
|
println!("cargo:rustc-link-search=native={}", &out_dir);
|
||||||
|
|
||||||
println!("cargo:rerun-if-changed=build.rs");
|
println!("cargo:rerun-if-changed=build.rs");
|
||||||
|
@ -1,197 +0,0 @@
|
|||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#define CMPLOG_MAP_W 65536
|
|
||||||
#define CMPLOG_MAP_H 32
|
|
||||||
|
|
||||||
#define CMPLOG_KIND_INS 0
|
|
||||||
#define CMPLOG_KIND_RTN 1
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
#define RETADDR (uintptr_t)_ReturnAddress()
|
|
||||||
#else
|
|
||||||
#define RETADDR (uintptr_t)__builtin_return_address(0)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef struct CmpLogHeader {
|
|
||||||
uint16_t hits;
|
|
||||||
uint8_t shape;
|
|
||||||
uint8_t kind;
|
|
||||||
} CmpLogHeader;
|
|
||||||
|
|
||||||
typedef struct CmpLogOperands {
|
|
||||||
uint64_t v0;
|
|
||||||
uint64_t v1;
|
|
||||||
} CmpLogOperands;
|
|
||||||
|
|
||||||
typedef struct CmpLogMap {
|
|
||||||
CmpLogHeader headers[CMPLOG_MAP_W];
|
|
||||||
CmpLogOperands operands[CMPLOG_MAP_W][CMPLOG_MAP_H];
|
|
||||||
} CmpLogMap;
|
|
||||||
|
|
||||||
extern CmpLogMap libafl_cmplog_map;
|
|
||||||
|
|
||||||
extern uint8_t libafl_cmplog_enabled;
|
|
||||||
|
|
||||||
#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
|
|
||||||
#elif defined(_MSC_VER)
|
|
||||||
#pragma comment(linker, "/alternatename:__sanitizer_cov_trace_const_cmp1=__sanitizer_cov_trace_cmp1")
|
|
||||||
#pragma comment(linker, "/alternatename:__sanitizer_cov_trace_const_cmp2=__sanitizer_cov_trace_cmp2")
|
|
||||||
#pragma comment(linker, "/alternatename:__sanitizer_cov_trace_const_cmp4=__sanitizer_cov_trace_cmp4")
|
|
||||||
#pragma comment(linker, "/alternatename:__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) {
|
|
||||||
|
|
||||||
if (!libafl_cmplog_enabled) return;
|
|
||||||
|
|
||||||
uintptr_t k = RETADDR;
|
|
||||||
k = (k >> 4) ^ (k << 8);
|
|
||||||
k &= CMPLOG_MAP_W - 1;
|
|
||||||
|
|
||||||
uint16_t hits;
|
|
||||||
if (libafl_cmplog_map.headers[k].kind != CMPLOG_KIND_INS) {
|
|
||||||
libafl_cmplog_map.headers[k].kind = CMPLOG_KIND_INS;
|
|
||||||
libafl_cmplog_map.headers[k].hits = 1;
|
|
||||||
libafl_cmplog_map.headers[k].shape = 1;
|
|
||||||
hits = 0;
|
|
||||||
} else {
|
|
||||||
hits = libafl_cmplog_map.headers[k].hits++;
|
|
||||||
if (libafl_cmplog_map.headers[k].shape < 1) {
|
|
||||||
libafl_cmplog_map.headers[k].shape = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
hits &= CMPLOG_MAP_H - 1;
|
|
||||||
libafl_cmplog_map.operands[k][hits].v0 = (uint64_t)arg1;
|
|
||||||
libafl_cmplog_map.operands[k][hits].v1 = (uint64_t)arg2;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void __sanitizer_cov_trace_cmp2(uint16_t arg1, uint16_t arg2) {
|
|
||||||
|
|
||||||
if (!libafl_cmplog_enabled) return;
|
|
||||||
|
|
||||||
uintptr_t k = RETADDR;
|
|
||||||
k = (k >> 4) ^ (k << 8);
|
|
||||||
k &= CMPLOG_MAP_W - 1;
|
|
||||||
|
|
||||||
uint16_t hits;
|
|
||||||
if (libafl_cmplog_map.headers[k].kind != CMPLOG_KIND_INS) {
|
|
||||||
libafl_cmplog_map.headers[k].kind = CMPLOG_KIND_INS;
|
|
||||||
libafl_cmplog_map.headers[k].hits = 1;
|
|
||||||
libafl_cmplog_map.headers[k].shape = 2;
|
|
||||||
hits = 0;
|
|
||||||
} else {
|
|
||||||
hits = libafl_cmplog_map.headers[k].hits++;
|
|
||||||
if (libafl_cmplog_map.headers[k].shape < 2) {
|
|
||||||
libafl_cmplog_map.headers[k].shape = 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
hits &= CMPLOG_MAP_H - 1;
|
|
||||||
libafl_cmplog_map.operands[k][hits].v0 = (uint64_t)arg1;
|
|
||||||
libafl_cmplog_map.operands[k][hits].v1 = (uint64_t)arg2;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void __sanitizer_cov_trace_cmp4(uint32_t arg1, uint32_t arg2) {
|
|
||||||
|
|
||||||
if (!libafl_cmplog_enabled) return;
|
|
||||||
|
|
||||||
uintptr_t k = RETADDR;
|
|
||||||
k = (k >> 4) ^ (k << 8);
|
|
||||||
k &= CMPLOG_MAP_W - 1;
|
|
||||||
|
|
||||||
uint16_t hits;
|
|
||||||
if (libafl_cmplog_map.headers[k].kind != CMPLOG_KIND_INS) {
|
|
||||||
libafl_cmplog_map.headers[k].kind = CMPLOG_KIND_INS;
|
|
||||||
libafl_cmplog_map.headers[k].hits = 1;
|
|
||||||
libafl_cmplog_map.headers[k].shape = 4;
|
|
||||||
hits = 0;
|
|
||||||
} else {
|
|
||||||
hits = libafl_cmplog_map.headers[k].hits++;
|
|
||||||
if (libafl_cmplog_map.headers[k].shape < 4) {
|
|
||||||
libafl_cmplog_map.headers[k].shape = 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
hits &= CMPLOG_MAP_H - 1;
|
|
||||||
libafl_cmplog_map.operands[k][hits].v0 = (uint64_t)arg1;
|
|
||||||
libafl_cmplog_map.operands[k][hits].v1 = (uint64_t)arg2;
|
|
||||||
}
|
|
||||||
|
|
||||||
void __sanitizer_cov_trace_cmp8(uint64_t arg1, uint64_t arg2) {
|
|
||||||
|
|
||||||
if (!libafl_cmplog_enabled) return;
|
|
||||||
|
|
||||||
uintptr_t k = RETADDR;
|
|
||||||
k = (k >> 4) ^ (k << 8);
|
|
||||||
k &= CMPLOG_MAP_W - 1;
|
|
||||||
|
|
||||||
uint16_t hits;
|
|
||||||
if (libafl_cmplog_map.headers[k].kind != CMPLOG_KIND_INS) {
|
|
||||||
libafl_cmplog_map.headers[k].kind = CMPLOG_KIND_INS;
|
|
||||||
libafl_cmplog_map.headers[k].hits = 1;
|
|
||||||
libafl_cmplog_map.headers[k].shape = 8;
|
|
||||||
hits = 0;
|
|
||||||
} else {
|
|
||||||
hits = libafl_cmplog_map.headers[k].hits++;
|
|
||||||
if (libafl_cmplog_map.headers[k].shape < 8) {
|
|
||||||
libafl_cmplog_map.headers[k].shape = 8;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
hits &= CMPLOG_MAP_H - 1;
|
|
||||||
libafl_cmplog_map.operands[k][hits].v0 = (uint64_t)arg1;
|
|
||||||
libafl_cmplog_map.operands[k][hits].v1 = (uint64_t)arg2;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void __sanitizer_cov_trace_switch(uint64_t val, uint64_t *cases) {
|
|
||||||
|
|
||||||
if (!libafl_cmplog_enabled) return;
|
|
||||||
|
|
||||||
uint8_t shape = (uint8_t)cases[1];
|
|
||||||
if (shape) {
|
|
||||||
shape /= 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (uint64_t i = 0; i < cases[0]; i++) {
|
|
||||||
|
|
||||||
uintptr_t k = RETADDR + i;
|
|
||||||
k = (k >> 4) ^ (k << 8);
|
|
||||||
k &= CMPLOG_MAP_W - 1;
|
|
||||||
|
|
||||||
uint16_t hits;
|
|
||||||
if (libafl_cmplog_map.headers[k].kind != CMPLOG_KIND_INS) {
|
|
||||||
libafl_cmplog_map.headers[k].kind = CMPLOG_KIND_INS;
|
|
||||||
libafl_cmplog_map.headers[k].hits = 1;
|
|
||||||
libafl_cmplog_map.headers[k].shape = shape;
|
|
||||||
hits = 0;
|
|
||||||
} else {
|
|
||||||
hits = libafl_cmplog_map.headers[k].hits++;
|
|
||||||
if (libafl_cmplog_map.headers[k].shape < shape) {
|
|
||||||
libafl_cmplog_map.headers[k].shape = shape;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
hits &= CMPLOG_MAP_H - 1;
|
|
||||||
libafl_cmplog_map.operands[k][hits].v0 = val;
|
|
||||||
libafl_cmplog_map.operands[k][hits].v1 = cases[i + 2];
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
55
libafl_targets/src/cmplog.h
Normal file
55
libafl_targets/src/cmplog.h
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
#ifndef __LIBAFL_TARGETS_CMPLOG__
|
||||||
|
#define __LIBAFL_TARGETS_CMPLOG__
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
#define CMPLOG_MAP_W 65536
|
||||||
|
#define CMPLOG_MAP_H 32
|
||||||
|
|
||||||
|
#define CMPLOG_KIND_INS 0
|
||||||
|
#define CMPLOG_KIND_RTN 1
|
||||||
|
|
||||||
|
typedef struct CmpLogHeader {
|
||||||
|
uint16_t hits;
|
||||||
|
uint8_t shape;
|
||||||
|
uint8_t kind;
|
||||||
|
} CmpLogHeader;
|
||||||
|
|
||||||
|
typedef struct CmpLogOperands {
|
||||||
|
uint64_t v0;
|
||||||
|
uint64_t v1;
|
||||||
|
} CmpLogOperands;
|
||||||
|
|
||||||
|
typedef struct CmpLogMap {
|
||||||
|
CmpLogHeader headers[CMPLOG_MAP_W];
|
||||||
|
CmpLogOperands operands[CMPLOG_MAP_W][CMPLOG_MAP_H];
|
||||||
|
} CmpLogMap;
|
||||||
|
|
||||||
|
extern CmpLogMap libafl_cmplog_map;
|
||||||
|
|
||||||
|
extern uint8_t libafl_cmplog_enabled;
|
||||||
|
|
||||||
|
static void __libafl_targets_cmplog(uintptr_t k, uint8_t shape, uint64_t arg1, uint64_t arg2) {
|
||||||
|
|
||||||
|
if (!libafl_cmplog_enabled) return;
|
||||||
|
|
||||||
|
uint16_t hits;
|
||||||
|
if (libafl_cmplog_map.headers[k].kind != CMPLOG_KIND_INS) {
|
||||||
|
libafl_cmplog_map.headers[k].kind = CMPLOG_KIND_INS;
|
||||||
|
libafl_cmplog_map.headers[k].hits = 1;
|
||||||
|
libafl_cmplog_map.headers[k].shape = shape;
|
||||||
|
hits = 0;
|
||||||
|
} else {
|
||||||
|
hits = libafl_cmplog_map.headers[k].hits++;
|
||||||
|
if (libafl_cmplog_map.headers[k].shape < shape) {
|
||||||
|
libafl_cmplog_map.headers[k].shape = shape;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hits &= CMPLOG_MAP_H - 1;
|
||||||
|
libafl_cmplog_map.operands[k][hits].v0 = arg1;
|
||||||
|
libafl_cmplog_map.operands[k][hits].v1 = arg2;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -1,6 +1,16 @@
|
|||||||
//! `CmpLog` logs and reports back values touched during fuzzing.
|
//! `CmpLog` logs and reports back values touched during fuzzing.
|
||||||
//! The values will then be used in subsequent mutations.
|
//! The values will then be used in subsequent mutations.
|
||||||
|
|
||||||
|
use libafl::{
|
||||||
|
bolts::{ownedref::OwnedRefMut, tuples::Named},
|
||||||
|
executors::HasExecHooks,
|
||||||
|
observers::{CmpMap, CmpObserver, CmpValues, Observer},
|
||||||
|
state::HasMetadata,
|
||||||
|
Error,
|
||||||
|
};
|
||||||
|
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
// TODO compile time flag
|
// TODO compile time flag
|
||||||
/// The `CmpLogMap` W value
|
/// The `CmpLogMap` W value
|
||||||
pub const CMPLOG_MAP_W: usize = 65536;
|
pub const CMPLOG_MAP_W: usize = 65536;
|
||||||
@ -9,6 +19,8 @@ pub const CMPLOG_MAP_H: usize = 32;
|
|||||||
/// The `CmpLog` map size
|
/// The `CmpLog` map size
|
||||||
pub const CMPLOG_MAP_SIZE: usize = CMPLOG_MAP_W * CMPLOG_MAP_H;
|
pub const CMPLOG_MAP_SIZE: usize = CMPLOG_MAP_W * CMPLOG_MAP_H;
|
||||||
|
|
||||||
|
big_array! { BigArray; }
|
||||||
|
|
||||||
/// `CmpLog` instruction kind
|
/// `CmpLog` instruction kind
|
||||||
pub const CMPLOG_KIND_INS: u8 = 0;
|
pub const CMPLOG_KIND_INS: u8 = 0;
|
||||||
/// `CmpLog` return kind
|
/// `CmpLog` return kind
|
||||||
@ -16,7 +28,7 @@ pub const CMPLOG_KIND_RTN: u8 = 1;
|
|||||||
|
|
||||||
/// The header for `CmpLog` hits.
|
/// The header for `CmpLog` hits.
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Serialize, Deserialize, Default, Debug, Clone, Copy)]
|
||||||
pub struct CmpLogHeader {
|
pub struct CmpLogHeader {
|
||||||
hits: u16,
|
hits: u16,
|
||||||
shape: u8,
|
shape: u8,
|
||||||
@ -25,17 +37,94 @@ pub struct CmpLogHeader {
|
|||||||
|
|
||||||
/// The operands logged during `CmpLog`.
|
/// The operands logged during `CmpLog`.
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Serialize, Deserialize, Default, Debug, Clone, Copy)]
|
||||||
pub struct CmpLogOperands(u64, u64);
|
pub struct CmpLogOperands(u64, u64);
|
||||||
|
|
||||||
/// A struct containing the `CmpLog` metadata for a `LibAFL` run.
|
/// A struct containing the `CmpLog` metadata for a `LibAFL` run.
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Serialize, Deserialize, Debug, Clone, Copy)]
|
||||||
pub struct CmpLogMap {
|
pub struct CmpLogMap {
|
||||||
|
#[serde(with = "BigArray")]
|
||||||
headers: [CmpLogHeader; CMPLOG_MAP_W],
|
headers: [CmpLogHeader; CMPLOG_MAP_W],
|
||||||
|
#[serde(with = "BigArray")]
|
||||||
operands: [[CmpLogOperands; CMPLOG_MAP_H]; CMPLOG_MAP_W],
|
operands: [[CmpLogOperands; CMPLOG_MAP_H]; CMPLOG_MAP_W],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for CmpLogMap {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
headers: [CmpLogHeader {
|
||||||
|
hits: 0,
|
||||||
|
shape: 0,
|
||||||
|
kind: 0,
|
||||||
|
}; CMPLOG_MAP_W],
|
||||||
|
operands: [[CmpLogOperands(0, 0); CMPLOG_MAP_H]; CMPLOG_MAP_W],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CmpMap for CmpLogMap {
|
||||||
|
fn len(&self) -> usize {
|
||||||
|
CMPLOG_MAP_W
|
||||||
|
}
|
||||||
|
|
||||||
|
fn executions_for(&self, idx: usize) -> usize {
|
||||||
|
self.headers[idx].hits as usize
|
||||||
|
}
|
||||||
|
|
||||||
|
fn usable_executions_for(&self, idx: usize) -> usize {
|
||||||
|
if self.executions_for(idx) < CMPLOG_MAP_H {
|
||||||
|
self.executions_for(idx)
|
||||||
|
} else {
|
||||||
|
CMPLOG_MAP_H
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn values_of(&self, idx: usize, execution: usize) -> CmpValues {
|
||||||
|
if self.headers[idx].kind == CMPLOG_KIND_INS {
|
||||||
|
match self.headers[idx].shape {
|
||||||
|
1 => {
|
||||||
|
return CmpValues::U8((
|
||||||
|
self.operands[idx][execution].0 as u8,
|
||||||
|
self.operands[idx][execution].1 as u8,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
2 => {
|
||||||
|
return CmpValues::U16((
|
||||||
|
self.operands[idx][execution].0 as u16,
|
||||||
|
self.operands[idx][execution].1 as u16,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
4 => {
|
||||||
|
return CmpValues::U32((
|
||||||
|
self.operands[idx][execution].0 as u32,
|
||||||
|
self.operands[idx][execution].1 as u32,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
8 => {
|
||||||
|
return CmpValues::U64((
|
||||||
|
self.operands[idx][execution].0 as u64,
|
||||||
|
self.operands[idx][execution].1 as u64,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// TODO bytes
|
||||||
|
CmpValues::Bytes((vec![], vec![]))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reset(&mut self) -> Result<(), Error> {
|
||||||
|
self.headers = [CmpLogHeader {
|
||||||
|
hits: 0,
|
||||||
|
shape: 0,
|
||||||
|
kind: 0,
|
||||||
|
}; CMPLOG_MAP_W];
|
||||||
|
self.operands = [[CmpLogOperands(0, 0); CMPLOG_MAP_H]; CMPLOG_MAP_W];
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// The global `CmpLog` map for the current `LibAFL` run.
|
/// The global `CmpLog` map for the current `LibAFL` run.
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub static mut libafl_cmplog_map: CmpLogMap = CmpLogMap {
|
pub static mut libafl_cmplog_map: CmpLogMap = CmpLogMap {
|
||||||
@ -54,3 +143,88 @@ pub use libafl_cmplog_map as CMPLOG_MAP;
|
|||||||
pub static mut libafl_cmplog_enabled: u8 = 0;
|
pub static mut libafl_cmplog_enabled: u8 = 0;
|
||||||
|
|
||||||
pub use libafl_cmplog_enabled as CMPLOG_ENABLED;
|
pub use libafl_cmplog_enabled as CMPLOG_ENABLED;
|
||||||
|
|
||||||
|
/// A [`CmpObserver`] observer for `CmpLog`
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
pub struct CmpLogObserver<'a> {
|
||||||
|
map: OwnedRefMut<'a, CmpLogMap>,
|
||||||
|
size: Option<OwnedRefMut<'a, usize>>,
|
||||||
|
add_meta: bool,
|
||||||
|
name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> CmpObserver<CmpLogMap> for CmpLogObserver<'a> {
|
||||||
|
/// Get the number of usable cmps (all by default)
|
||||||
|
fn usable_count(&self) -> usize {
|
||||||
|
match &self.size {
|
||||||
|
None => self.map().len(),
|
||||||
|
Some(o) => *o.as_ref(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn map(&self) -> &CmpLogMap {
|
||||||
|
self.map.as_ref()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn map_mut(&mut self) -> &mut CmpLogMap {
|
||||||
|
self.map.as_mut()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Observer for CmpLogObserver<'a> {}
|
||||||
|
|
||||||
|
impl<'a, EM, I, S, Z> HasExecHooks<EM, I, S, Z> for CmpLogObserver<'a>
|
||||||
|
where
|
||||||
|
S: HasMetadata,
|
||||||
|
{
|
||||||
|
fn pre_exec(
|
||||||
|
&mut self,
|
||||||
|
_fuzzer: &mut Z,
|
||||||
|
_state: &mut S,
|
||||||
|
_mgr: &mut EM,
|
||||||
|
_input: &I,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
self.map.as_mut().reset()?;
|
||||||
|
unsafe {
|
||||||
|
CMPLOG_ENABLED = 1;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn post_exec(
|
||||||
|
&mut self,
|
||||||
|
_fuzzer: &mut Z,
|
||||||
|
state: &mut S,
|
||||||
|
_mgr: &mut EM,
|
||||||
|
_input: &I,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
unsafe {
|
||||||
|
CMPLOG_ENABLED = 0;
|
||||||
|
}
|
||||||
|
if self.add_meta {
|
||||||
|
self.add_cmpvalues_meta(state);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Named for CmpLogObserver<'a> {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
&self.name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> CmpLogObserver<'a> {
|
||||||
|
/// Creates a new [`CmpLogObserver`] with the given name.
|
||||||
|
#[must_use]
|
||||||
|
pub fn new(name: &'static str, map: &'a mut CmpLogMap, add_meta: bool) -> Self {
|
||||||
|
Self {
|
||||||
|
name: name.to_string(),
|
||||||
|
size: None,
|
||||||
|
add_meta,
|
||||||
|
map: OwnedRefMut::Ref(map),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO with_size
|
||||||
|
}
|
||||||
|
29
libafl_targets/src/common.h
Normal file
29
libafl_targets/src/common.h
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
#ifndef __LIBAFL_TARGETS_COMMON__
|
||||||
|
#define __LIBAFL_TARGETS_COMMON__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#define RETADDR (uintptr_t)_ReturnAddress()
|
||||||
|
#define EXPORT_FN __declspec(dllexport)
|
||||||
|
#else
|
||||||
|
#define RETADDR (uintptr_t)__builtin_return_address(0)
|
||||||
|
#define EXPORT_FN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
#define MAX(a, b) \
|
||||||
|
({ \
|
||||||
|
\
|
||||||
|
__typeof__(a) _a = (a); \
|
||||||
|
__typeof__(b) _b = (b); \
|
||||||
|
_a > _b ? _a : _b; \
|
||||||
|
\
|
||||||
|
})
|
||||||
|
#else
|
||||||
|
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
10
libafl_targets/src/coverage.rs
Normal file
10
libafl_targets/src/coverage.rs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
//! Coverage maps as static mut array
|
||||||
|
|
||||||
|
// TODO compile time flag
|
||||||
|
/// The map size for the edges map.
|
||||||
|
pub const EDGES_MAP_SIZE: usize = 65536;
|
||||||
|
|
||||||
|
/// The map for edges.
|
||||||
|
pub static mut EDGES_MAP: [u8; EDGES_MAP_SIZE] = [0; EDGES_MAP_SIZE];
|
||||||
|
/// The max count of edges tracked.
|
||||||
|
pub static mut MAX_EDGES_NUM: usize = 0;
|
@ -1,27 +1,25 @@
|
|||||||
//! `libafl_targets` contains runtime code, injected in the target itself during compilation.
|
//! `libafl_targets` contains runtime code, injected in the target itself during compilation.
|
||||||
|
|
||||||
#[cfg(any(feature = "pcguard_edges", feature = "pcguard_hitcounts"))]
|
#[macro_use]
|
||||||
pub mod pcguard;
|
extern crate serde_big_array;
|
||||||
#[cfg(any(feature = "pcguard_edges", feature = "pcguard_hitcounts"))]
|
|
||||||
pub use pcguard::*;
|
#[cfg(any(feature = "sancov_pcguard_edges", feature = "sancov_pcguard_hitcounts"))]
|
||||||
|
pub mod sancov_pcguard;
|
||||||
|
#[cfg(any(feature = "sancov_pcguard_edges", feature = "sancov_pcguard_hitcounts"))]
|
||||||
|
pub use sancov_pcguard::*;
|
||||||
|
|
||||||
#[cfg(feature = "libfuzzer")]
|
#[cfg(feature = "libfuzzer")]
|
||||||
pub mod libfuzzer;
|
pub mod libfuzzer;
|
||||||
#[cfg(feature = "libfuzzer")]
|
#[cfg(feature = "libfuzzer")]
|
||||||
pub use libfuzzer::*;
|
pub use libfuzzer::*;
|
||||||
|
|
||||||
#[cfg(all(feature = "value_profile", feature = "cmplog"))]
|
pub mod coverage;
|
||||||
#[cfg(not(any(doc, feature = "clippy")))]
|
pub use coverage::*;
|
||||||
compile_error!("the libafl_targets `value_profile` and `cmplog` features are mutually exclusive.");
|
|
||||||
|
|
||||||
#[cfg(feature = "value_profile")]
|
|
||||||
pub mod value_profile;
|
pub mod value_profile;
|
||||||
#[cfg(feature = "value_profile")]
|
|
||||||
pub use value_profile::*;
|
pub use value_profile::*;
|
||||||
|
|
||||||
#[cfg(feature = "cmplog")]
|
|
||||||
pub mod cmplog;
|
pub mod cmplog;
|
||||||
#[cfg(feature = "cmplog")]
|
|
||||||
pub use cmplog::*;
|
pub use cmplog::*;
|
||||||
|
|
||||||
pub mod drcov;
|
pub mod drcov;
|
||||||
|
@ -13,8 +13,6 @@
|
|||||||
#define LIBFUZZER_MSVC 0
|
#define LIBFUZZER_MSVC 0
|
||||||
#endif // _MSC_VER
|
#endif // _MSC_VER
|
||||||
|
|
||||||
#define EXPORT_FN __declspec(dllexport)
|
|
||||||
|
|
||||||
// From Libfuzzer
|
// From Libfuzzer
|
||||||
// Intermediate macro to ensure the parameter is expanded before stringified.
|
// Intermediate macro to ensure the parameter is expanded before stringified.
|
||||||
#define STRINGIFY_(A) #A
|
#define STRINGIFY_(A) #A
|
||||||
|
@ -1,35 +1,11 @@
|
|||||||
#include <stdio.h>
|
#include "common.h"
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
// TODO compile time flag
|
#ifdef SANCOV_VALUE_PROFILE
|
||||||
#define MAP_SIZE 65536
|
#include "value_profile.h"
|
||||||
|
|
||||||
extern uint8_t libafl_cmp_map[MAP_SIZE];
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
#define RETADDR (uintptr_t)_ReturnAddress()
|
|
||||||
#else
|
|
||||||
#define RETADDR (uintptr_t)__builtin_return_address(0)
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __GNUC__
|
#ifdef SANCOV_CMPLOG
|
||||||
#define MAX(a, b) \
|
#include "cmplog.h"
|
||||||
({ \
|
|
||||||
\
|
|
||||||
__typeof__(a) _a = (a); \
|
|
||||||
__typeof__(b) _b = (b); \
|
|
||||||
_a > _b ? _a : _b; \
|
|
||||||
\
|
|
||||||
})
|
|
||||||
#else
|
|
||||||
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
#include <intrin.h>
|
|
||||||
#define __builtin_popcount __popcnt
|
|
||||||
#define __builtin_popcountll __popcnt64
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(__APPLE__)
|
#if defined(__APPLE__)
|
||||||
@ -56,8 +32,15 @@ void __sanitizer_cov_trace_cmp1(uint8_t arg1, uint8_t arg2) {
|
|||||||
|
|
||||||
uintptr_t k = RETADDR;
|
uintptr_t k = RETADDR;
|
||||||
k = (k >> 4) ^ (k << 8);
|
k = (k >> 4) ^ (k << 8);
|
||||||
|
|
||||||
|
#ifdef SANCOV_VALUE_PROFILE
|
||||||
k &= MAP_SIZE - 1;
|
k &= MAP_SIZE - 1;
|
||||||
libafl_cmp_map[k] = MAX(libafl_cmp_map[k], (__builtin_popcount(~(arg1 ^ arg2))));
|
__libafl_targets_value_profile1(k, arg1, arg2);
|
||||||
|
#endif
|
||||||
|
#ifdef SANCOV_CMPLOG
|
||||||
|
k &= CMPLOG_MAP_W - 1;
|
||||||
|
__libafl_targets_cmplog(k, 1, (uint64_t)arg1, (uint64_t)arg2);
|
||||||
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,8 +48,15 @@ void __sanitizer_cov_trace_cmp2(uint16_t arg1, uint16_t arg2) {
|
|||||||
|
|
||||||
uintptr_t k = RETADDR;
|
uintptr_t k = RETADDR;
|
||||||
k = (k >> 4) ^ (k << 8);
|
k = (k >> 4) ^ (k << 8);
|
||||||
|
|
||||||
|
#ifdef SANCOV_VALUE_PROFILE
|
||||||
k &= MAP_SIZE - 1;
|
k &= MAP_SIZE - 1;
|
||||||
libafl_cmp_map[k] = MAX(libafl_cmp_map[k], (__builtin_popcount(~(arg1 ^ arg2))));
|
__libafl_targets_value_profile2(k, arg1, arg2);
|
||||||
|
#endif
|
||||||
|
#ifdef SANCOV_CMPLOG
|
||||||
|
k &= CMPLOG_MAP_W - 1;
|
||||||
|
__libafl_targets_cmplog(k, 2, (uint64_t)arg1, (uint64_t)arg2);
|
||||||
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,8 +64,15 @@ void __sanitizer_cov_trace_cmp4(uint32_t arg1, uint32_t arg2) {
|
|||||||
|
|
||||||
uintptr_t k = RETADDR;
|
uintptr_t k = RETADDR;
|
||||||
k = (k >> 4) ^ (k << 8);
|
k = (k >> 4) ^ (k << 8);
|
||||||
|
|
||||||
|
#ifdef SANCOV_VALUE_PROFILE
|
||||||
k &= MAP_SIZE - 1;
|
k &= MAP_SIZE - 1;
|
||||||
libafl_cmp_map[k] = MAX(libafl_cmp_map[k], (__builtin_popcount(~(arg1 ^ arg2))));
|
__libafl_targets_value_profile4(k, arg1, arg2);
|
||||||
|
#endif
|
||||||
|
#ifdef SANCOV_CMPLOG
|
||||||
|
k &= CMPLOG_MAP_W - 1;
|
||||||
|
__libafl_targets_cmplog(k, 4, (uint64_t)arg1, (uint64_t)arg2);
|
||||||
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,35 +80,51 @@ void __sanitizer_cov_trace_cmp8(uint64_t arg1, uint64_t arg2) {
|
|||||||
|
|
||||||
uintptr_t k = RETADDR;
|
uintptr_t k = RETADDR;
|
||||||
k = (k >> 4) ^ (k << 8);
|
k = (k >> 4) ^ (k << 8);
|
||||||
|
|
||||||
|
#ifdef SANCOV_VALUE_PROFILE
|
||||||
k &= MAP_SIZE - 1;
|
k &= MAP_SIZE - 1;
|
||||||
libafl_cmp_map[k] = MAX(libafl_cmp_map[k], (__builtin_popcountll(~(arg1 ^ arg2))));
|
__libafl_targets_value_profile8(k, arg1, arg2);
|
||||||
|
#endif
|
||||||
|
#ifdef SANCOV_CMPLOG
|
||||||
|
k &= CMPLOG_MAP_W - 1;
|
||||||
|
__libafl_targets_cmplog(k, 8, (uint64_t)arg1, (uint64_t)arg2);
|
||||||
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void __sanitizer_cov_trace_switch(uint64_t val, uint64_t *cases) {
|
void __sanitizer_cov_trace_switch(uint64_t val, uint64_t *cases) {
|
||||||
|
|
||||||
uintptr_t rt = RETADDR;
|
uintptr_t rt = RETADDR;
|
||||||
if (cases[1] == 64) {
|
|
||||||
|
|
||||||
for (uint64_t i = 0; i < cases[0]; i++) {
|
// if (!cases[1]) return;
|
||||||
|
|
||||||
uintptr_t k = rt + i;
|
for (uint64_t i = 0; i < cases[0]; i++) {
|
||||||
k = (k >> 4) ^ (k << 8);
|
|
||||||
k &= MAP_SIZE - 1;
|
|
||||||
libafl_cmp_map[k] = MAX(libafl_cmp_map[k], (__builtin_popcountll(~(val ^ cases[i + 2]))));
|
|
||||||
|
|
||||||
|
uintptr_t k = rt + i;
|
||||||
|
k = (k >> 4) ^ (k << 8);
|
||||||
|
// val , cases[i + 2]
|
||||||
|
#ifdef SANCOV_VALUE_PROFILE
|
||||||
|
k &= MAP_SIZE - 1;
|
||||||
|
switch (cases[1]) {
|
||||||
|
case 8:
|
||||||
|
__libafl_targets_value_profile1(k, (uint8_t)val, (uint8_t)cases[i + 2]);
|
||||||
|
break;
|
||||||
|
case 16:
|
||||||
|
__libafl_targets_value_profile2(k, (uint16_t)val, (uint16_t)cases[i + 2]);
|
||||||
|
break;
|
||||||
|
case 32:
|
||||||
|
__libafl_targets_value_profile4(k, (uint32_t)val, (uint32_t)cases[i + 2]);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
__libafl_targets_value_profile8(k, val, cases[i + 2]);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef SANCOV_CMPLOG
|
||||||
|
k &= CMPLOG_MAP_W - 1;
|
||||||
|
__libafl_targets_cmplog(k, cases[1] / 8, val, cases[i + 2]);
|
||||||
|
#endif
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
for (uint64_t i = 0; i < cases[0]; i++) {
|
|
||||||
|
|
||||||
uintptr_t k = rt + i;
|
|
||||||
k = (k >> 4) ^ (k << 8);
|
|
||||||
k &= MAP_SIZE - 1;
|
|
||||||
libafl_cmp_map[k] = MAX(libafl_cmp_map[k], (__builtin_popcount(~(val ^ cases[i + 2]))));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -1,34 +1,27 @@
|
|||||||
//! [`LLVM` `PcGuard`](https://clang.llvm.org/docs/SanitizerCoverage.html#tracing-pcs-with-guards) runtime for `LibAFL`.
|
//! [`LLVM` `PcGuard`](https://clang.llvm.org/docs/SanitizerCoverage.html#tracing-pcs-with-guards) runtime for `LibAFL`.
|
||||||
|
|
||||||
#[cfg(all(feature = "pcguard_edges", feature = "pcguard_hitcounts"))]
|
use crate::coverage::{EDGES_MAP, EDGES_MAP_SIZE, MAX_EDGES_NUM};
|
||||||
|
|
||||||
|
#[cfg(all(feature = "sancov_pcguard_edges", feature = "sancov_pcguard_hitcounts"))]
|
||||||
#[cfg(not(any(doc, feature = "clippy")))]
|
#[cfg(not(any(doc, feature = "clippy")))]
|
||||||
compile_error!(
|
compile_error!(
|
||||||
"the libafl_targets `pcguard_edges` and `pcguard_hitcounts` features are mutually exclusive."
|
"the libafl_targets `pcguard_edges` and `pcguard_hitcounts` features are mutually exclusive."
|
||||||
);
|
);
|
||||||
|
|
||||||
// TODO compile time flag
|
|
||||||
/// The map size for `SanCov` edges.
|
|
||||||
pub const EDGES_MAP_SIZE: usize = 65536;
|
|
||||||
|
|
||||||
/// The map for `SanCov` edges.
|
|
||||||
pub static mut EDGES_MAP: [u8; EDGES_MAP_SIZE] = [0; EDGES_MAP_SIZE];
|
|
||||||
//pub static mut CMP_MAP: [u8; EDGES_MAP_SIZE] = [0; EDGES_MAP_SIZE];
|
|
||||||
/// The max count of edges tracked.
|
|
||||||
pub static mut MAX_EDGES_NUM: usize = 0;
|
|
||||||
|
|
||||||
/// Callback for sancov `pc_guard` - usually called by `llvm` on each block or edge.
|
/// Callback for sancov `pc_guard` - usually called by `llvm` on each block or edge.
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
/// Dereferences `guard`, reads the position from there, then dereferences the [`EDGES_MAP`] at that position.
|
/// Dereferences `guard`, reads the position from there, then dereferences the [`EDGES_MAP`] at that position.
|
||||||
/// Should usually not be called directly.
|
/// Should usually not be called directly.
|
||||||
|
#[cfg(any(feature = "sancov_pcguard_edges", feature = "sancov_pcguard_hitcounts"))]
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn __sanitizer_cov_trace_pc_guard(guard: *mut u32) {
|
pub unsafe extern "C" fn __sanitizer_cov_trace_pc_guard(guard: *mut u32) {
|
||||||
let pos = *guard as usize;
|
let pos = *guard as usize;
|
||||||
#[cfg(feature = "pcguard_edges")]
|
#[cfg(feature = "sancov_pcguard_edges")]
|
||||||
{
|
{
|
||||||
*EDGES_MAP.get_unchecked_mut(pos) = 1;
|
*EDGES_MAP.get_unchecked_mut(pos) = 1;
|
||||||
}
|
}
|
||||||
#[cfg(feature = "pcguard_hitcounts")]
|
#[cfg(feature = "sancov_pcguard_hitcounts")]
|
||||||
{
|
{
|
||||||
let val = (*EDGES_MAP.get_unchecked(pos) as u8).wrapping_add(1);
|
let val = (*EDGES_MAP.get_unchecked(pos) as u8).wrapping_add(1);
|
||||||
*EDGES_MAP.get_unchecked_mut(pos) = val;
|
*EDGES_MAP.get_unchecked_mut(pos) = val;
|
||||||
@ -39,6 +32,7 @@ pub unsafe extern "C" fn __sanitizer_cov_trace_pc_guard(guard: *mut u32) {
|
|||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
/// Dereferences at `start` and writes to it.
|
/// Dereferences at `start` and writes to it.
|
||||||
|
#[cfg(any(feature = "sancov_pcguard_edges", feature = "sancov_pcguard_hitcounts"))]
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn __sanitizer_cov_trace_pc_guard_init(mut start: *mut u32, stop: *mut u32) {
|
pub unsafe extern "C" fn __sanitizer_cov_trace_pc_guard_init(mut start: *mut u32, stop: *mut u32) {
|
||||||
if start == stop || *start != 0 {
|
if start == stop || *start != 0 {
|
41
libafl_targets/src/value_profile.h
Normal file
41
libafl_targets/src/value_profile.h
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
#ifndef __LIBAFL_TARGETS_VALUE_PROFILE__
|
||||||
|
#define __LIBAFL_TARGETS_VALUE_PROFILE__
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
// TODO compile time flag
|
||||||
|
#define MAP_SIZE 65536
|
||||||
|
|
||||||
|
extern uint8_t libafl_cmp_map[MAP_SIZE];
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#include <intrin.h>
|
||||||
|
#define __builtin_popcount __popcnt
|
||||||
|
#define __builtin_popcountll __popcnt64
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void __libafl_targets_value_profile1(uintptr_t k, uint8_t arg1, uint8_t arg2) {
|
||||||
|
|
||||||
|
libafl_cmp_map[k] = MAX(libafl_cmp_map[k], (__builtin_popcount(~(arg1 ^ arg2))));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __libafl_targets_value_profile2(uintptr_t k, uint16_t arg1, uint16_t arg2) {
|
||||||
|
|
||||||
|
libafl_cmp_map[k] = MAX(libafl_cmp_map[k], (__builtin_popcount(~(arg1 ^ arg2))));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __libafl_targets_value_profile4(uintptr_t k, uint32_t arg1, uint32_t arg2) {
|
||||||
|
|
||||||
|
libafl_cmp_map[k] = MAX(libafl_cmp_map[k], (__builtin_popcount(~(arg1 ^ arg2))));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __libafl_targets_value_profile8(uintptr_t k, uint64_t arg1, uint64_t arg2) {
|
||||||
|
|
||||||
|
libafl_cmp_map[k] = MAX(libafl_cmp_map[k], (__builtin_popcountll(~(arg1 ^ arg2))));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
Loading…
x
Reference in New Issue
Block a user