libfuzzer_stb_image with build.rs and win32 fixes
This commit is contained in:
parent
40fe286cf9
commit
7564ce1e87
@ -12,7 +12,6 @@ members = [
|
|||||||
"libafl_targets",
|
"libafl_targets",
|
||||||
|
|
||||||
#example fuzzers
|
#example fuzzers
|
||||||
#"fuzzers/libfuzzer_libpng",
|
|
||||||
"fuzzers/frida_libpng",
|
"fuzzers/frida_libpng",
|
||||||
"fuzzers/libfuzzer_libmozjpeg",
|
"fuzzers/libfuzzer_libmozjpeg",
|
||||||
"fuzzers/libfuzzer_libpng_cmpalloc",
|
"fuzzers/libfuzzer_libpng_cmpalloc",
|
||||||
@ -20,4 +19,5 @@ members = [
|
|||||||
]
|
]
|
||||||
exclude = [
|
exclude = [
|
||||||
"fuzzers/libfuzzer_libpng",
|
"fuzzers/libfuzzer_libpng",
|
||||||
|
"fuzzers/libfuzzer_stb_image",
|
||||||
]
|
]
|
||||||
|
@ -18,7 +18,7 @@ debug = true
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
libafl = { path = "../../libafl/" }
|
libafl = { path = "../../libafl/" }
|
||||||
libafl_targets = { path = "../../libafl_targets/", features = ["sancov", "libfuzzer_compatibility"] }
|
libafl_targets = { path = "../../libafl_targets/", features = ["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/" }
|
||||||
|
|
||||||
|
@ -6,18 +6,26 @@ fn main() {
|
|||||||
if args.len() > 1 {
|
if args.len() > 1 {
|
||||||
let mut dir = env::current_exe().unwrap();
|
let mut dir = env::current_exe().unwrap();
|
||||||
dir.pop();
|
dir.pop();
|
||||||
ClangWrapper::new("clang", "clang++")
|
|
||||||
.from_args(&args)
|
let mut cc = ClangWrapper::new("clang", "clang++");
|
||||||
|
cc.from_args(&args)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.add_arg("-fsanitize-coverage=trace-pc-guard".into())
|
.add_arg("-fsanitize-coverage=trace-pc-guard".into())
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.add_link_arg(
|
.add_link_arg(
|
||||||
dir.join(format!("{}libfuzzer_libpng.{}", LIB_PREFIX, LIB_EXT))
|
dir.join(format!("{}libfuzzer_stb_image.{}", LIB_PREFIX, LIB_EXT))
|
||||||
.display()
|
.display()
|
||||||
.to_string(),
|
.to_string(),
|
||||||
)
|
)
|
||||||
.unwrap()
|
|
||||||
.run()
|
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
// Libraries needed by libafl on Windows
|
||||||
|
#[cfg(windows)]
|
||||||
|
cc.add_link_arg("-lws2_32".into())
|
||||||
|
.unwrap()
|
||||||
|
.add_link_arg("-lBcrypt".into())
|
||||||
|
.unwrap()
|
||||||
|
.add_link_arg("-lAdvapi32".into())
|
||||||
|
.unwrap();
|
||||||
|
cc.run().unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,19 +6,27 @@ fn main() {
|
|||||||
if args.len() > 1 {
|
if args.len() > 1 {
|
||||||
let mut dir = env::current_exe().unwrap();
|
let mut dir = env::current_exe().unwrap();
|
||||||
dir.pop();
|
dir.pop();
|
||||||
ClangWrapper::new("clang", "clang++")
|
|
||||||
.is_cpp()
|
let mut cc = ClangWrapper::new("clang", "clang++");
|
||||||
|
cc.is_cpp()
|
||||||
.from_args(&args)
|
.from_args(&args)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.add_arg("-fsanitize-coverage=trace-pc-guard".into())
|
.add_arg("-fsanitize-coverage=trace-pc-guard".into())
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.add_link_arg(
|
.add_link_arg(
|
||||||
dir.join(format!("{}libfuzzer_libpng.{}", LIB_PREFIX, LIB_EXT))
|
dir.join(format!("{}libfuzzer_stb_image.{}", LIB_PREFIX, LIB_EXT))
|
||||||
.display()
|
.display()
|
||||||
.to_string(),
|
.to_string(),
|
||||||
)
|
)
|
||||||
.unwrap()
|
|
||||||
.run()
|
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
// Libraries needed by libafl on Windows
|
||||||
|
#[cfg(windows)]
|
||||||
|
cc.add_link_arg("-lws2_32".into())
|
||||||
|
.unwrap()
|
||||||
|
.add_link_arg("-lBcrypt".into())
|
||||||
|
.unwrap()
|
||||||
|
.add_link_arg("-lAdvapi32".into())
|
||||||
|
.unwrap();
|
||||||
|
cc.run().unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -107,9 +107,11 @@ fn fuzz(corpus_dirs: Vec<PathBuf>, objective_dir: PathBuf, broker_port: u16) ->
|
|||||||
let stage = StdMutationalStage::new(mutator);
|
let stage = StdMutationalStage::new(mutator);
|
||||||
|
|
||||||
// A fuzzer with just one stage and a minimization+queue policy to get testcasess from the corpus
|
// A fuzzer with just one stage and a minimization+queue policy to get testcasess from the corpus
|
||||||
let scheduler = IndexesLenTimeMinimizerCorpusScheduler::new(QueueCorpusScheduler::new());
|
|
||||||
let mut fuzzer = StdFuzzer::new(tuple_list!(stage));
|
let mut fuzzer = StdFuzzer::new(tuple_list!(stage));
|
||||||
|
|
||||||
|
// A minimization+queue policy to get testcasess from the corpus
|
||||||
|
let scheduler = IndexesLenTimeMinimizerCorpusScheduler::new(QueueCorpusScheduler::new());
|
||||||
|
|
||||||
// The wrapped harness function, calling out to the LLVM-style harness
|
// The wrapped harness function, calling out to the LLVM-style harness
|
||||||
let mut harness = |buf: &[u8]| {
|
let mut harness = |buf: &[u8]| {
|
||||||
libfuzzer_test_one_input(buf);
|
libfuzzer_test_one_input(buf);
|
||||||
@ -119,7 +121,7 @@ fn fuzz(corpus_dirs: Vec<PathBuf>, objective_dir: PathBuf, broker_port: u16) ->
|
|||||||
// Create the executor for an in-process function with just one observer for edge coverage
|
// Create the executor for an in-process function with just one observer for edge coverage
|
||||||
let mut executor = TimeoutExecutor::new(
|
let mut executor = TimeoutExecutor::new(
|
||||||
InProcessExecutor::new(
|
InProcessExecutor::new(
|
||||||
"in-process(edges)",
|
"in-process(edges,time)",
|
||||||
&mut harness,
|
&mut harness,
|
||||||
tuple_list!(edges_observer, TimeObserver::new("time")),
|
tuple_list!(edges_observer, TimeObserver::new("time")),
|
||||||
&mut state,
|
&mut state,
|
||||||
|
1
fuzzers/libfuzzer_stb_image/.gitignore
vendored
Normal file
1
fuzzers/libfuzzer_stb_image/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
libpng-*
|
24
fuzzers/libfuzzer_stb_image/Cargo.toml
Normal file
24
fuzzers/libfuzzer_stb_image/Cargo.toml
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
[package]
|
||||||
|
name = "libfuzzer_stb_image"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Andrea Fioraldi <andreafioraldi@gmail.com>", "Dominik Maier <domenukk@gmail.com>"]
|
||||||
|
edition = "2018"
|
||||||
|
build = "build.rs"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = ["std"]
|
||||||
|
std = []
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
lto = true
|
||||||
|
codegen-units = 1
|
||||||
|
opt-level = 3
|
||||||
|
debug = true
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
libafl = { path = "../../libafl/" }
|
||||||
|
libafl_targets = { path = "../../libafl_targets/", features = ["pcguard_edges", "libfuzzer"] }
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
cc = { version = "1.0", features = ["parallel"] }
|
||||||
|
num_cpus = "1.0"
|
43
fuzzers/libfuzzer_stb_image/README.md
Normal file
43
fuzzers/libfuzzer_stb_image/README.md
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
# Libfuzzer for libpng
|
||||||
|
|
||||||
|
This folder contains an example fuzzer for libpng, using LLMP for fast multi-process fuzzing and crash detection.
|
||||||
|
To show off crash detection, we added a ud2 instruction to the harness, edit harness.cc if you want a non-crashing example.
|
||||||
|
It has been tested on Linux.
|
||||||
|
|
||||||
|
## Build
|
||||||
|
|
||||||
|
To build this example, run `cargo build --release`.
|
||||||
|
This will build the library with the fuzzer (src/lib.rs) with the libfuzzer compatibility layer and the SanitizerCoverage runtime functions for coverage feedback.
|
||||||
|
In addition, it will build also two C and C++ compiler wrappers (bin/c(c/xx).rs) that you must use to compile the target.
|
||||||
|
|
||||||
|
Then download libpng from https://deac-fra.dl.sourceforge.net/project/libpng/libpng16/1.6.37/libpng-1.6.37.tar.xz and unpack the archive.
|
||||||
|
|
||||||
|
Now compile it with:
|
||||||
|
|
||||||
|
```
|
||||||
|
cd libpng-1.6.37
|
||||||
|
./configure
|
||||||
|
make CC=/path/to/libfuzzer_libpng/target/release/cc -j `nproc`
|
||||||
|
```
|
||||||
|
|
||||||
|
You can find the static lib at `libpng-1.6.37/.libs/libpng16.a`.
|
||||||
|
|
||||||
|
Now, we have to build the libfuzzer harness and link all togheter to create our fuzzer binary.
|
||||||
|
|
||||||
|
```
|
||||||
|
/path/to/libfuzzer_libpng/target/debug/cxx /path/to/libfuzzer_libpng/harness.cc libpng-1.6.37/.libs/libpng16.a -I libpng-1.6.37/ -o fuzzer -lz -lm
|
||||||
|
```
|
||||||
|
|
||||||
|
Afterwards, the fuzzer will be ready to run simply executing `./fuzzer`.
|
||||||
|
|
||||||
|
## Run
|
||||||
|
|
||||||
|
The first time you run the binary, the broker will open a tcp port (currently on port `1337`), waiting for fuzzer clients to connect. This port is local and only used for the initial handshake. All further communication happens via shared map, to be independent of the kernel.
|
||||||
|
|
||||||
|
Each following execution will run a fuzzer client.
|
||||||
|
As this example uses in-process fuzzing, we added a Restarting Event Manager (`setup_restarting_mgr`).
|
||||||
|
This means each client will start itself again to listen for crashes and timeouts.
|
||||||
|
By restarting the actual fuzzer, it can recover from these exit conditions.
|
||||||
|
|
||||||
|
In any real-world scenario, you should use `taskset` to pin each client to an empty CPU core, the lib does not pick an empty core automatically (yet).
|
||||||
|
|
27
fuzzers/libfuzzer_stb_image/build.rs
Normal file
27
fuzzers/libfuzzer_stb_image/build.rs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
// build.rs
|
||||||
|
|
||||||
|
use std::env;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let out_dir = env::var_os("OUT_DIR").unwrap();
|
||||||
|
let out_dir = out_dir.to_string_lossy().to_string();
|
||||||
|
|
||||||
|
println!("cargo:rerun-if-changed=harness.c");
|
||||||
|
|
||||||
|
// Enforce clang for its -fsanitize-coverage support.
|
||||||
|
std::env::set_var("CC", "clang");
|
||||||
|
std::env::set_var("CXX", "clang++");
|
||||||
|
|
||||||
|
cc::Build::new()
|
||||||
|
// Use sanitizer coverage to track the edges in the PUT
|
||||||
|
.flag("-fsanitize-coverage=trace-pc-guard")
|
||||||
|
// Take advantage of LTO (needs lld-link set in your cargo config)
|
||||||
|
//.flag("-flto=thin")
|
||||||
|
.flag("-Wno-sign-compare")
|
||||||
|
.file("./harness.c")
|
||||||
|
.compile("harness");
|
||||||
|
|
||||||
|
println!("cargo:rustc-link-search=native={}", &out_dir);
|
||||||
|
|
||||||
|
println!("cargo:rerun-if-changed=build.rs");
|
||||||
|
}
|
BIN
fuzzers/libfuzzer_stb_image/corpus/not_kitty.png
Normal file
BIN
fuzzers/libfuzzer_stb_image/corpus/not_kitty.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 218 B |
BIN
fuzzers/libfuzzer_stb_image/corpus/not_kitty_alpha.png
Normal file
BIN
fuzzers/libfuzzer_stb_image/corpus/not_kitty_alpha.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 376 B |
BIN
fuzzers/libfuzzer_stb_image/corpus/not_kitty_gamma.png
Normal file
BIN
fuzzers/libfuzzer_stb_image/corpus/not_kitty_gamma.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 228 B |
BIN
fuzzers/libfuzzer_stb_image/corpus/not_kitty_icc.png
Normal file
BIN
fuzzers/libfuzzer_stb_image/corpus/not_kitty_icc.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 427 B |
61
fuzzers/libfuzzer_stb_image/harness.c
Normal file
61
fuzzers/libfuzzer_stb_image/harness.c
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#define STBI_ASSERT(x)
|
||||||
|
#define STBI_NO_SIMD
|
||||||
|
#define STBI_NO_LINEAR
|
||||||
|
#define STBI_NO_STDIO
|
||||||
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
|
|
||||||
|
#include "stb_image.h"
|
||||||
|
|
||||||
|
int target_func(const uint8_t *buf, size_t size) {
|
||||||
|
|
||||||
|
/*printf("BUF (%ld): ", size);
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
printf("%02X", buf[i]);
|
||||||
|
}
|
||||||
|
printf("\n");*/
|
||||||
|
|
||||||
|
if (size == 0) return 0;
|
||||||
|
|
||||||
|
switch (buf[0]) {
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
if (buf[1] == 0x44) {
|
||||||
|
//__builtin_trap();
|
||||||
|
return 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case 0xff:
|
||||||
|
if (buf[2] == 0xff) {
|
||||||
|
if (buf[1] == 0x44) {
|
||||||
|
//*(char *)(0xdeadbeef) = 1;
|
||||||
|
return 9;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
|
||||||
|
{return target_func(data, size);
|
||||||
|
int x, y, channels;
|
||||||
|
|
||||||
|
if(!stbi_info_from_memory(data, size, &x, &y, &channels)) return 0;
|
||||||
|
|
||||||
|
/* exit if the image is larger than ~80MB */
|
||||||
|
if(y && x > (80000000 / 4) / y) return 0;
|
||||||
|
|
||||||
|
unsigned char *img = stbi_load_from_memory(data, size, &x, &y, &channels, 4);
|
||||||
|
|
||||||
|
free(img);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
150
fuzzers/libfuzzer_stb_image/src/main.rs
Normal file
150
fuzzers/libfuzzer_stb_image/src/main.rs
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
//! A libfuzzer-like fuzzer with llmp-multithreading support and restarts
|
||||||
|
//! The example harness is built for stb_image.
|
||||||
|
|
||||||
|
use std::{env, path::PathBuf};
|
||||||
|
|
||||||
|
use libafl::{
|
||||||
|
bolts::{shmem::StdShMem, tuples::tuple_list},
|
||||||
|
corpus::{
|
||||||
|
Corpus, InMemoryCorpus, IndexesLenTimeMinimizerCorpusScheduler, OnDiskCorpus,
|
||||||
|
QueueCorpusScheduler,
|
||||||
|
},
|
||||||
|
events::setup_restarting_mgr,
|
||||||
|
executors::{inprocess::InProcessExecutor, ExitKind},
|
||||||
|
feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback},
|
||||||
|
fuzzer::{Fuzzer, StdFuzzer},
|
||||||
|
mutators::scheduled::{havoc_mutations, StdScheduledMutator},
|
||||||
|
mutators::token_mutations::Tokens,
|
||||||
|
observers::{HitcountsMapObserver, StdMapObserver, TimeObserver},
|
||||||
|
stages::mutational::StdMutationalStage,
|
||||||
|
state::{HasCorpus, HasMetadata, State},
|
||||||
|
stats::SimpleStats,
|
||||||
|
utils::{current_nanos, StdRand},
|
||||||
|
Error,
|
||||||
|
};
|
||||||
|
|
||||||
|
use libafl_targets::{libfuzzer_initialize, libfuzzer_test_one_input, EDGES_MAP, MAX_EDGES_NUM};
|
||||||
|
|
||||||
|
/// The main fn, no_mangle as it is a C main
|
||||||
|
pub fn main() {
|
||||||
|
// Registry the metadata types used in this fuzzer
|
||||||
|
// Needed only on no_std
|
||||||
|
//RegistryBuilder::register::<Tokens>();
|
||||||
|
|
||||||
|
println!(
|
||||||
|
"Workdir: {:?}",
|
||||||
|
env::current_dir().unwrap().to_string_lossy().to_string()
|
||||||
|
);
|
||||||
|
fuzz(
|
||||||
|
vec![PathBuf::from("./corpus")],
|
||||||
|
PathBuf::from("./crashes"),
|
||||||
|
1337,
|
||||||
|
)
|
||||||
|
.expect("An error occurred while fuzzing");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The actual fuzzer
|
||||||
|
fn fuzz(corpus_dirs: Vec<PathBuf>, objective_dir: PathBuf, broker_port: u16) -> Result<(), Error> {
|
||||||
|
// 'While the stats are state, they are usually used in the broker - which is likely never restarted
|
||||||
|
let stats = SimpleStats::new(|s| println!("{}", s));
|
||||||
|
|
||||||
|
// The restarting state will spawn the same process again as child, then restarted it each time it crashes.
|
||||||
|
let (state, mut restarting_mgr) =
|
||||||
|
match setup_restarting_mgr::<_, _, StdShMem, _>(stats, broker_port) {
|
||||||
|
Ok(res) => res,
|
||||||
|
Err(err) => match err {
|
||||||
|
Error::ShuttingDown => {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
panic!("Failed to setup the restarter: {}", err);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create an observation channel using the coverage map
|
||||||
|
let edges_observer = HitcountsMapObserver::new(unsafe {
|
||||||
|
StdMapObserver::new("edges", &mut EDGES_MAP, MAX_EDGES_NUM)
|
||||||
|
});
|
||||||
|
|
||||||
|
// If not restarting, create a State from scratch
|
||||||
|
let mut state = state.unwrap_or_else(|| {
|
||||||
|
State::new(
|
||||||
|
// RNG
|
||||||
|
StdRand::with_seed(current_nanos()),
|
||||||
|
// Corpus that will be evolved, we keep it in memory for performance
|
||||||
|
InMemoryCorpus::new(),
|
||||||
|
// Feedbacks to rate the interestingness of an input
|
||||||
|
tuple_list!(
|
||||||
|
MaxMapFeedback::new_with_observer_track(&edges_observer, true, false),
|
||||||
|
TimeFeedback::new()
|
||||||
|
),
|
||||||
|
// Corpus in which we store solutions (crashes in this example),
|
||||||
|
// on disk so the user can get them after stopping the fuzzer
|
||||||
|
OnDiskCorpus::new(objective_dir).unwrap(),
|
||||||
|
// Feedbacks to recognize an input as solution
|
||||||
|
tuple_list!(CrashFeedback::new()),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
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 stage = StdMutationalStage::new(mutator);
|
||||||
|
|
||||||
|
// A fuzzer with just one stage and a minimization+queue policy to get testcasess from the corpus
|
||||||
|
let mut fuzzer = StdFuzzer::new(tuple_list!(stage));
|
||||||
|
|
||||||
|
// A minimization+queue policy to get testcasess from the corpus
|
||||||
|
let scheduler = IndexesLenTimeMinimizerCorpusScheduler::new(QueueCorpusScheduler::new());
|
||||||
|
|
||||||
|
// The wrapped harness function, calling out to the LLVM-style harness
|
||||||
|
let mut harness = |buf: &[u8]| {
|
||||||
|
libfuzzer_test_one_input(buf);
|
||||||
|
ExitKind::Ok
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create the executor for an in-process function with just one observer for edge coverage
|
||||||
|
let mut executor = InProcessExecutor::new(
|
||||||
|
"in-process(edges,time)",
|
||||||
|
&mut harness,
|
||||||
|
tuple_list!(edges_observer, TimeObserver::new("time")),
|
||||||
|
&mut state,
|
||||||
|
&mut restarting_mgr,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
// The actual target run starts here.
|
||||||
|
// Call LLVMFUzzerInitialize() if present.
|
||||||
|
let args: Vec<String> = env::args().collect();
|
||||||
|
if libfuzzer_initialize(&args) == -1 {
|
||||||
|
println!("Warning: LLVMFuzzerInitialize failed with -1")
|
||||||
|
}
|
||||||
|
|
||||||
|
// In case the corpus is empty (on first run), reset
|
||||||
|
if state.corpus().count() < 1 {
|
||||||
|
state
|
||||||
|
.load_initial_inputs(&mut executor, &mut restarting_mgr, &scheduler, &corpus_dirs)
|
||||||
|
.expect(&format!(
|
||||||
|
"Failed to load initial corpus at {:?}",
|
||||||
|
&corpus_dirs
|
||||||
|
));
|
||||||
|
println!("We imported {} inputs from disk.", state.corpus().count());
|
||||||
|
}
|
||||||
|
|
||||||
|
fuzzer.fuzz_loop(&mut state, &mut executor, &mut restarting_mgr, &scheduler)?;
|
||||||
|
|
||||||
|
// Never reached
|
||||||
|
Ok(())
|
||||||
|
}
|
7762
fuzzers/libfuzzer_stb_image/stb_image.h
Normal file
7762
fuzzers/libfuzzer_stb_image/stb_image.h
Normal file
File diff suppressed because it is too large
Load Diff
@ -219,13 +219,13 @@ int load_stbi(const uint8_t *data, int size)
|
|||||||
|
|
||||||
extern "C"
|
extern "C"
|
||||||
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
|
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
|
||||||
//return target_func(Data, Size);
|
return target_func(Data, Size);
|
||||||
|
|
||||||
if(Size > 0x4000) return 0;
|
if(Size > 0x4000) return 0;
|
||||||
|
|
||||||
int size = Size;
|
int size = Size;
|
||||||
const unsigned char * data = Data;
|
const unsigned char * data = Data;
|
||||||
//return load_stbi(data, size);
|
return load_stbi(data, size);
|
||||||
return parse_pe(data, size);
|
//return parse_pe(data, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,8 +14,9 @@ use libafl::{
|
|||||||
events::setup_restarting_mgr,
|
events::setup_restarting_mgr,
|
||||||
executors::{inprocess::InProcessExecutor, ExitKind},
|
executors::{inprocess::InProcessExecutor, ExitKind},
|
||||||
feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback, TimeoutFeedback},
|
feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback, TimeoutFeedback},
|
||||||
fuzzer::{Fuzzer, HasCorpusScheduler, StdFuzzer},
|
fuzzer::{Fuzzer, StdFuzzer},
|
||||||
mutators::{scheduled::HavocBytesMutator, token_mutations::Tokens},
|
mutators::scheduled::{havoc_mutations, StdScheduledMutator},
|
||||||
|
mutators::token_mutations::Tokens,
|
||||||
observers::{HitcountsMapObserver, StdMapObserver, TimeObserver},
|
observers::{HitcountsMapObserver, StdMapObserver, TimeObserver},
|
||||||
stages::mutational::StdMutationalStage,
|
stages::mutational::StdMutationalStage,
|
||||||
state::{HasCorpus, HasMetadata, State},
|
state::{HasCorpus, HasMetadata, State},
|
||||||
@ -133,12 +134,12 @@ fn fuzz(corpus_dirs: Vec<PathBuf>, objective_dir: PathBuf, broker_port: u16) ->
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Setup a basic mutator with a mutational stage
|
// Setup a basic mutator with a mutational stage
|
||||||
let mutator = HavocBytesMutator::default();
|
let mutator = StdScheduledMutator::new(havoc_mutations());
|
||||||
let stage = StdMutationalStage::new(mutator);
|
let stage = StdMutationalStage::new(mutator);
|
||||||
|
|
||||||
// A fuzzer with just one stage and a minimization+queue policy to get testcasess from the corpus
|
// A fuzzer with just one stage and a minimization+queue policy to get testcasess from the corpus
|
||||||
let scheduler = IndexesLenTimeMinimizerCorpusScheduler::new(QueueCorpusScheduler::new());
|
let scheduler = IndexesLenTimeMinimizerCorpusScheduler::new(QueueCorpusScheduler::new());
|
||||||
let fuzzer = StdFuzzer::new(scheduler, tuple_list!(stage));
|
let mut fuzzer = StdFuzzer::new(tuple_list!(stage));
|
||||||
|
|
||||||
// Create the executor for an in-process function with just one observer for edge coverage
|
// Create the executor for an in-process function with just one observer for edge coverage
|
||||||
let mut executor = InProcessExecutor::new(
|
let mut executor = InProcessExecutor::new(
|
||||||
@ -160,12 +161,7 @@ fn fuzz(corpus_dirs: Vec<PathBuf>, objective_dir: PathBuf, broker_port: u16) ->
|
|||||||
// In case the corpus is empty (on first run), reset
|
// In case the corpus is empty (on first run), reset
|
||||||
if state.corpus().count() < 1 {
|
if state.corpus().count() < 1 {
|
||||||
state
|
state
|
||||||
.load_initial_inputs(
|
.load_initial_inputs(&mut executor, &mut restarting_mgr, &scheduler, &corpus_dirs)
|
||||||
&mut executor,
|
|
||||||
&mut restarting_mgr,
|
|
||||||
fuzzer.scheduler(),
|
|
||||||
&corpus_dirs,
|
|
||||||
)
|
|
||||||
.expect(&format!(
|
.expect(&format!(
|
||||||
"Failed to load initial corpus at {:?}",
|
"Failed to load initial corpus at {:?}",
|
||||||
&corpus_dirs
|
&corpus_dirs
|
||||||
@ -173,7 +169,7 @@ fn fuzz(corpus_dirs: Vec<PathBuf>, objective_dir: PathBuf, broker_port: u16) ->
|
|||||||
println!("We imported {} inputs from disk.", state.corpus().count());
|
println!("We imported {} inputs from disk.", state.corpus().count());
|
||||||
}
|
}
|
||||||
|
|
||||||
fuzzer.fuzz_loop(&mut state, &mut executor, &mut restarting_mgr)?;
|
fuzzer.fuzz_loop(&mut state, &mut executor, &mut restarting_mgr, &scheduler)?;
|
||||||
|
|
||||||
// Never reached
|
// Never reached
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -6,8 +6,10 @@ edition = "2018"
|
|||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = []
|
default = []
|
||||||
sancov = []
|
pcguard_edges = []
|
||||||
libfuzzer_compatibility = []
|
pcguard_hitcounts = []
|
||||||
|
libfuzzer = []
|
||||||
|
pcguard = ["pcguard_hitcounts"]
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
cc = { version = "1.0", features = ["parallel"] }
|
cc = { version = "1.0", features = ["parallel"] }
|
||||||
|
@ -7,13 +7,16 @@ fn main() {
|
|||||||
let out_dir = out_dir.to_string_lossy().to_string();
|
let out_dir = out_dir.to_string_lossy().to_string();
|
||||||
//let out_dir_path = Path::new(&out_dir);
|
//let out_dir_path = Path::new(&out_dir);
|
||||||
|
|
||||||
#[cfg(feature = "libfuzzer_compatibility")]
|
std::env::set_var("CC", "clang");
|
||||||
|
std::env::set_var("CXX", "clang++");
|
||||||
|
|
||||||
|
#[cfg(feature = "libfuzzer")]
|
||||||
{
|
{
|
||||||
println!("cargo:rerun-if-changed=libfuzzer_compatibility.c");
|
println!("cargo:rerun-if-changed=libfuzzer_compatibility.c");
|
||||||
|
|
||||||
cc::Build::new()
|
cc::Build::new()
|
||||||
.file("libfuzzer_compatibility.c")
|
.file("libfuzzer_compatibility.c")
|
||||||
.compile("libfuzzer-compatibility");
|
.compile("libfuzzer_compatibility");
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("cargo:rustc-link-search=native={}", &out_dir);
|
println!("cargo:rustc-link-search=native={}", &out_dir);
|
||||||
|
@ -13,6 +13,8 @@
|
|||||||
#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
|
||||||
@ -32,7 +34,7 @@
|
|||||||
__pragma(comment(linker, "/alternatename:" WIN_SYM_PREFIX STRINGIFY( \
|
__pragma(comment(linker, "/alternatename:" WIN_SYM_PREFIX STRINGIFY( \
|
||||||
Name) "=" WIN_SYM_PREFIX STRINGIFY(Default)))
|
Name) "=" WIN_SYM_PREFIX STRINGIFY(Default)))
|
||||||
|
|
||||||
#define CHECK_WEAK_FN(Name) (Name != &Name##Def)
|
#define CHECK_WEAK_FN(Name) ((void*)Name != (void*)&Name##Def)
|
||||||
#else
|
#else
|
||||||
// Declare external functions as weak to allow them to default to a specified
|
// Declare external functions as weak to allow them to default to a specified
|
||||||
// function if not defined explicitly. We must use weak symbols because clang's
|
// function if not defined explicitly. We must use weak symbols because clang's
|
||||||
@ -49,6 +51,8 @@
|
|||||||
EXTERNAL_FUNC(NAME, NAME##Def) RETURN_TYPE NAME FUNC_SIG
|
EXTERNAL_FUNC(NAME, NAME##Def) RETURN_TYPE NAME FUNC_SIG
|
||||||
#else
|
#else
|
||||||
|
|
||||||
|
#define EXPORT_FN
|
||||||
|
|
||||||
// Declare these symbols as weak to allow them to be optionally defined.
|
// Declare these symbols as weak to allow them to be optionally defined.
|
||||||
#define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \
|
#define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \
|
||||||
__attribute__((weak, visibility("default"))) RETURN_TYPE NAME FUNC_SIG
|
__attribute__((weak, visibility("default"))) RETURN_TYPE NAME FUNC_SIG
|
||||||
@ -68,11 +72,11 @@ EXT_FUNC(LLVMFuzzerCustomCrossOver, size_t,
|
|||||||
|
|
||||||
#undef EXT_FUNC
|
#undef EXT_FUNC
|
||||||
|
|
||||||
int libafl_targets_has_libfuzzer_init() {
|
EXPORT_FN int libafl_targets_has_libfuzzer_init() {
|
||||||
return CHECK_WEAK_FN(LLVMFuzzerInitialize);
|
return CHECK_WEAK_FN(LLVMFuzzerInitialize);
|
||||||
}
|
}
|
||||||
|
|
||||||
int libafl_targets_libfuzzer_init(int *argc, char ***argv) {
|
EXPORT_FN int libafl_targets_libfuzzer_init(int *argc, char ***argv) {
|
||||||
if (libafl_targets_has_libfuzzer_init()) {
|
if (libafl_targets_has_libfuzzer_init()) {
|
||||||
return LLVMFuzzerInitialize(argc, argv);
|
return LLVMFuzzerInitialize(argc, argv);
|
||||||
} else {
|
} else {
|
||||||
|
@ -1,17 +1,9 @@
|
|||||||
#[cfg(feature = "sancov")]
|
#[cfg(any(feature = "pcguard_edges", feature = "pcguard_hitcounts"))]
|
||||||
pub mod sancov;
|
pub mod pcguard;
|
||||||
#[cfg(feature = "sancov")]
|
#[cfg(any(feature = "pcguard_edges", feature = "pcguard_hitcounts"))]
|
||||||
pub use sancov::*;
|
pub use pcguard::*;
|
||||||
|
|
||||||
#[cfg(feature = "libfuzzer_compatibility")]
|
#[cfg(feature = "libfuzzer")]
|
||||||
pub mod libfuzzer_compatibility;
|
pub mod libfuzzer;
|
||||||
#[cfg(feature = "libfuzzer_compatibility")]
|
#[cfg(feature = "libfuzzer")]
|
||||||
pub use libfuzzer_compatibility::*;
|
pub use libfuzzer::*;
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
#[test]
|
|
||||||
fn it_works() {
|
|
||||||
assert_eq!(2 + 2, 4);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -1,15 +1,27 @@
|
|||||||
|
#[cfg(all(feature = "pcguard_edges", feature = "pcguard_hitcounts"))]
|
||||||
|
compile_error!(
|
||||||
|
"the libafl_targets `pcguard_edges` and `pcguard_hitcounts` features are mutually exclusive."
|
||||||
|
);
|
||||||
|
|
||||||
// TODO compile time flag
|
// TODO compile time flag
|
||||||
pub const MAP_SIZE: usize = 65536;
|
pub const MAP_SIZE: usize = 65536;
|
||||||
|
|
||||||
pub static mut EDGES_MAP: [u8; MAP_SIZE] = [0; MAP_SIZE];
|
pub static mut EDGES_MAP: [u8; MAP_SIZE] = [0; MAP_SIZE];
|
||||||
pub static mut CMP_MAP: [u8; MAP_SIZE] = [0; MAP_SIZE];
|
//pub static mut CMP_MAP: [u8; MAP_SIZE] = [0; MAP_SIZE];
|
||||||
pub static mut MAX_EDGES_NUM: usize = 0;
|
pub static mut MAX_EDGES_NUM: usize = 0;
|
||||||
|
|
||||||
#[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;
|
||||||
let val = (EDGES_MAP[pos] as u8).wrapping_add(1);
|
#[cfg(feature = "pcguard_edges")]
|
||||||
EDGES_MAP[pos] = val;
|
{
|
||||||
|
*EDGES_MAP.get_unchecked_mut(pos) = 1;
|
||||||
|
}
|
||||||
|
#[cfg(feature = "pcguard_hitcounts")]
|
||||||
|
{
|
||||||
|
let val = (*EDGES_MAP.get_unchecked(pos) as u8).wrapping_add(1);
|
||||||
|
*EDGES_MAP.get_unchecked_mut(pos) = val;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
Loading…
x
Reference in New Issue
Block a user