fuzzbench harness (#165)
* starting to build fuzzbench harness * fuzzbench updated * fuzzbench example readme * removed dummy files * Intial de-luxe dockerfile added * added to dockerignore * more fuzzbench * dockerfile * final dockerfile fun * fuzzing fixes, switched rand, build fixes * fmt * added dummy fuzzone * silence wrapper output * clippy * logfile fixes * adopt changes to libafl-cc * various fixes
This commit is contained in:
parent
1faadec106
commit
dea21da5c3
@ -25,3 +25,7 @@ test.dict
|
|||||||
# Ignore all built fuzzers
|
# Ignore all built fuzzers
|
||||||
fuzzer_*
|
fuzzer_*
|
||||||
AFLplusplus
|
AFLplusplus
|
||||||
|
|
||||||
|
# Ignore common dummy and logfiles
|
||||||
|
*.log
|
||||||
|
a
|
||||||
|
4
.gitignore
vendored
4
.gitignore
vendored
@ -25,3 +25,7 @@ test.dict
|
|||||||
# Ignore all built fuzzers
|
# Ignore all built fuzzers
|
||||||
fuzzer_*
|
fuzzer_*
|
||||||
AFLplusplus
|
AFLplusplus
|
||||||
|
|
||||||
|
# Ignore common dummy and logfiles
|
||||||
|
*.log
|
||||||
|
a
|
||||||
|
113
Dockerfile
113
Dockerfile
@ -1,79 +1,58 @@
|
|||||||
#
|
# syntax=docker/dockerfile:1.2
|
||||||
# This Dockerfile for LibAFL uses rust:bullseye as base.
|
|
||||||
#
|
|
||||||
|
|
||||||
FROM rust:bullseye AS libafl
|
FROM rust:bullseye AS libafl
|
||||||
LABEL "maintainer"="afl++ team <afl@aflplus.plus>"
|
LABEL "maintainer"="afl++ team <afl@aflplus.plus>"
|
||||||
LABEL "about"="AFLplusplus docker image"
|
LABEL "about"="LibAFL Docker image"
|
||||||
|
|
||||||
ARG DEBIAN_FRONTEND=noninteractive
|
# install sccache to cache subsequent builds of dependencies
|
||||||
|
RUN cargo install sccache
|
||||||
|
|
||||||
RUN sh -c 'echo set encoding=utf-8 > /root/.vimrc' \
|
ENV HOME=/root
|
||||||
echo "export PS1='"'[LibAFL \h] \w$(__git_ps1) \$ '"'" >> ~/.bashrc
|
ENV SCCACHE_CACHE_SIZE="1G"
|
||||||
|
ENV SCCACHE_DIR=$HOME/.cache/sccache
|
||||||
|
ENV RUSTC_WRAPPER="/usr/local/cargo/bin/sccache"
|
||||||
ENV IS_DOCKER="1"
|
ENV IS_DOCKER="1"
|
||||||
|
RUN sh -c 'echo set encoding=utf-8 > /root/.vimrc' \
|
||||||
|
echo "export PS1='"'[LibAFL \h] \w$(__git_ps1) \$ '"'" >> ~/.bashrc && \
|
||||||
|
mkdir ~/.cargo && \
|
||||||
|
echo "[build]\nrustc-wrapper = \"${RUSTC_WRAPPER}\"" >> ~/.cargo/config
|
||||||
|
|
||||||
|
RUN rustup component add rustfmt clippy
|
||||||
|
|
||||||
|
# Install clang 11, common build tools
|
||||||
|
RUN apt update && apt install -y build-essential gdb git wget clang clang-tools libc++-11-dev libc++abi-11-dev
|
||||||
|
|
||||||
# Copy a dummy.rs and Cargo.toml first, so that dependencies are cached
|
# Copy a dummy.rs and Cargo.toml first, so that dependencies are cached
|
||||||
WORKDIR /libafl
|
WORKDIR /libafl
|
||||||
COPY Cargo.toml Cargo.toml
|
COPY Cargo.toml README.md ./
|
||||||
COPY README.md README.md
|
|
||||||
|
|
||||||
COPY libafl_derive/Cargo.toml libafl_derive/Cargo.toml
|
COPY libafl_derive/Cargo.toml libafl_derive/Cargo.toml
|
||||||
COPY scripts/dummy.rs libafl_derive/src/lib.rs
|
COPY scripts/dummy.rs libafl_derive/src/lib.rs
|
||||||
|
|
||||||
COPY libafl/Cargo.toml libafl/Cargo.toml
|
COPY libafl/Cargo.toml libafl/build.rs libafl/
|
||||||
COPY libafl/build.rs libafl/build.rs
|
|
||||||
COPY libafl/benches libafl/benches
|
COPY libafl/benches libafl/benches
|
||||||
COPY libafl/examples libafl/examples
|
COPY libafl/examples libafl/examples
|
||||||
COPY scripts/dummy.rs libafl/src/lib.rs
|
COPY scripts/dummy.rs libafl/src/lib.rs
|
||||||
|
|
||||||
COPY libafl_frida/Cargo.toml libafl_frida/Cargo.toml
|
COPY libafl_frida/Cargo.toml libafl_frida/build.rs libafl_frida/
|
||||||
COPY libafl_frida/build.rs libafl_frida/build.rs
|
|
||||||
COPY scripts/dummy.rs libafl_frida/src/lib.rs
|
COPY scripts/dummy.rs libafl_frida/src/lib.rs
|
||||||
|
COPY libafl_frida/src/gettls.c libafl_frida/src/gettls.c
|
||||||
|
|
||||||
COPY libafl_cc/Cargo.toml libafl_cc/Cargo.toml
|
COPY libafl_cc/Cargo.toml libafl_cc/Cargo.toml
|
||||||
COPY scripts/dummy.rs libafl_cc/src/lib.rs
|
COPY scripts/dummy.rs libafl_cc/src/lib.rs
|
||||||
|
|
||||||
COPY libafl_targets/Cargo.toml libafl_targets/Cargo.toml
|
COPY libafl_targets/Cargo.toml libafl_targets/build.rs libafl_targets/
|
||||||
COPY libafl_targets/build.rs libafl_targets/build.rs
|
COPY libafl_targets/src libafl_targets/src
|
||||||
COPY scripts/dummy.rs libafl_targets/src/lib.rs
|
COPY scripts/dummy.rs libafl_targets/src/lib.rs
|
||||||
|
|
||||||
COPY libafl_tests/Cargo.toml libafl_tests/Cargo.toml
|
COPY libafl_tests/Cargo.toml libafl_tests/build.rs libafl_tests/
|
||||||
COPY libafl_tests/build.rs libafl_tests/build.rs
|
|
||||||
COPY scripts/dummy.rs libafl_tests/src/lib.rs
|
COPY scripts/dummy.rs libafl_tests/src/lib.rs
|
||||||
|
|
||||||
|
RUN cargo build && cargo build --release
|
||||||
|
|
||||||
|
COPY scripts scripts
|
||||||
COPY docs docs
|
COPY docs docs
|
||||||
|
|
||||||
RUN cargo build && cargo build --release
|
|
||||||
|
|
||||||
# Pre-build dependencies for a few common fuzzers
|
# Pre-build dependencies for a few common fuzzers
|
||||||
COPY fuzzers/baby_fuzzer/Cargo.toml fuzzers/baby_fuzzer/Cargo.toml
|
|
||||||
COPY fuzzers/baby_fuzzer/README.md fuzzers/baby_fuzzer/README.md
|
|
||||||
COPY scripts/dummy.rs fuzzers/baby_fuzzer/src/main.rs
|
|
||||||
WORKDIR /libafl/fuzzers/baby_fuzzer
|
|
||||||
RUN cargo build && cargo build --release
|
|
||||||
WORKDIR /libafl
|
|
||||||
|
|
||||||
COPY fuzzers/forkserver_simple/Cargo.toml fuzzers/forkserver_simple/Cargo.toml
|
|
||||||
COPY fuzzers/forkserver_simple/README.md fuzzers/forkserver_simple/README.md
|
|
||||||
COPY scripts/dummy.rs fuzzers/forkserver_simple/src/main.rs
|
|
||||||
WORKDIR /libafl/fuzzers/forkserver_simple
|
|
||||||
RUN cargo build && cargo build --release
|
|
||||||
WORKDIR /libafl
|
|
||||||
|
|
||||||
COPY fuzzers/frida_libpng/Cargo.toml fuzzers/frida_libpng/Cargo.toml
|
|
||||||
COPY fuzzers/frida_libpng/README.md fuzzers/frida_libpng/README.md
|
|
||||||
COPY fuzzers/frida_libpng/build.rs fuzzers/frida_libpng/build.rs
|
|
||||||
COPY scripts/dummy.rs fuzzers/frida_libpng/src/main.rs
|
|
||||||
WORKDIR /libafl/fuzzers/frida_libpng
|
|
||||||
RUN cargo build && cargo build --release
|
|
||||||
WORKDIR /libafl
|
|
||||||
|
|
||||||
COPY fuzzers/generic_inmemory/Cargo.toml fuzzers/generic_inmemory/Cargo.toml
|
|
||||||
COPY fuzzers/generic_inmemory/README.md fuzzers/generic_inmemory/README.md
|
|
||||||
COPY scripts/dummy.rs fuzzers/generic_inmemory/src/main.rs
|
|
||||||
WORKDIR /libafl/fuzzers/generic_inmemory
|
|
||||||
RUN cargo build && cargo build --release
|
|
||||||
WORKDIR /libafl
|
|
||||||
|
|
||||||
# Dep chain:
|
# Dep chain:
|
||||||
# libafl_cc (independent)
|
# libafl_cc (independent)
|
||||||
@ -84,42 +63,22 @@ WORKDIR /libafl
|
|||||||
|
|
||||||
# Build once without source
|
# Build once without source
|
||||||
COPY libafl_cc/src libafl_cc/src
|
COPY libafl_cc/src libafl_cc/src
|
||||||
RUN touch libafl_cc/src/lib.rs && cargo build && cargo build --release
|
RUN touch libafl_cc/src/lib.rs
|
||||||
|
|
||||||
COPY libafl_derive/src libafl_derive/src
|
COPY libafl_derive/src libafl_derive/src
|
||||||
RUN touch libafl_derive/src/lib.rs && cargo build && cargo build --release
|
RUN touch libafl_derive/src/lib.rs
|
||||||
|
|
||||||
COPY libafl_tests/src libafl_tests/src
|
COPY libafl_tests/src libafl_tests/src
|
||||||
RUN touch libafl_tests/src/lib.rs && cargo build && cargo build --release
|
RUN touch libafl_tests/src/lib.rs
|
||||||
|
|
||||||
COPY libafl/src libafl/src
|
COPY libafl/src libafl/src
|
||||||
RUN touch libafl/src/lib.rs && cargo build && cargo build --release
|
RUN touch libafl/src/lib.rs
|
||||||
|
|
||||||
COPY libafl_targets/src libafl_targets/src
|
COPY libafl_targets/src libafl_targets/src
|
||||||
RUN touch libafl_targets/src/lib.rs && cargo build && cargo build --release
|
RUN touch libafl_targets/src/lib.rs
|
||||||
|
|
||||||
COPY libafl_frida/src libafl_frida/src
|
COPY libafl_frida/src libafl_frida/src
|
||||||
RUN touch libafl_frida/src/lib.rs && cargo build && cargo build --release
|
RUN touch libafl_frida/src/lib.rs
|
||||||
|
RUN cargo build && cargo build --release
|
||||||
|
|
||||||
# Copy fuzzers over
|
# Copy fuzzers over
|
||||||
COPY fuzzers/baby_fuzzer/src fuzzers/baby_fuzzer/src/src
|
COPY fuzzers fuzzers
|
||||||
RUN touch fuzzers/baby_fuzzer/src/main.rs
|
|
||||||
COPY fuzzers/forkserver_simple/corpus fuzzers/forkserver_simple/corpus
|
|
||||||
COPY fuzzers/forkserver_simple/src fuzzers/forkserver_simple/src
|
|
||||||
RUN touch fuzzers/forkserver_simple/src/main.rs
|
|
||||||
COPY fuzzers/frida_libpng/src fuzzers/frida_libpng/src
|
|
||||||
COPY fuzzers/frida_libpng/harness.cc fuzzers/frida_libpng/harness.cc
|
|
||||||
RUN touch fuzzers/frida_libpng/src/main.rs
|
|
||||||
COPY fuzzers/generic_inmemory/src fuzzers/generic_inmemory/src
|
|
||||||
COPY fuzzers/generic_inmemory/fuzz.c fuzzers/generic_inmemory/fuzz.c
|
|
||||||
RUN touch fuzzers/frida_libpng/src/main.rs
|
|
||||||
COPY fuzzers/libfuzzer_libmozjpeg fuzzers/libfuzzer_libmozjpg
|
|
||||||
COPY fuzzers/libfuzzer_libpng fuzzers/libfuzzer_libpng
|
|
||||||
COPY fuzzers/libfuzzer_libpng_launcher fuzzers/libfuzzer_libpng_launcher
|
|
||||||
COPY fuzzers/libfuzzer_reachability fuzzers/libfuzzer_reachability
|
|
||||||
COPY fuzzers/libfuzzer_stb_image fuzzers/libfuzzer_stb_image
|
|
||||||
|
|
||||||
#RUN ./scripts/build_all_fuzzers.sh
|
|
||||||
|
|
||||||
|
# RUN ./scripts/build_all_fuzzers.sh --no-fmt
|
||||||
|
|
||||||
ENTRYPOINT [ "/bin/bash" ]
|
ENTRYPOINT [ "/bin/bash" ]
|
||||||
|
1
fuzzers/fuzzbench/.gitignore
vendored
Normal file
1
fuzzers/fuzzbench/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
libpng-*
|
44
fuzzers/fuzzbench/Cargo.toml
Normal file
44
fuzzers/fuzzbench/Cargo.toml
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
[package]
|
||||||
|
name = "fuzzbench"
|
||||||
|
version = "0.3.2"
|
||||||
|
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
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
cc = { version = "1.0", features = ["parallel"] }
|
||||||
|
which = { version = "4.0.2" }
|
||||||
|
num_cpus = "1.0"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
libafl = { path = "../../libafl/" }
|
||||||
|
libafl_targets = { path = "../../libafl_targets/", features = ["sancov_pcguard_hitcounts", "sancov_cmplog", "libfuzzer"] }
|
||||||
|
# TODO Include it only when building cc
|
||||||
|
libafl_cc = { path = "../../libafl_cc/" }
|
||||||
|
clap = { version = "3.0.0-beta.2", features = ["default"] }
|
||||||
|
nix = "0.20.0"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
name = "fuzzbench"
|
||||||
|
crate-type = ["staticlib"]
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
# For c binaries
|
||||||
|
name = "libafl_cc"
|
||||||
|
path = "src/bin/libafl_cc.rs"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
# For cpp binaries
|
||||||
|
name = "libafl_cxx"
|
||||||
|
path = "src/bin/libafl_cc.rs"
|
||||||
|
|
17
fuzzers/fuzzbench/README.md
Normal file
17
fuzzers/fuzzbench/README.md
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
# Fuzzbench Harness
|
||||||
|
|
||||||
|
This folder contains an example fuzzer tailored for fuzzbench.
|
||||||
|
It uses the best possible setting, with the exception of a SimpleRestartingEventManager instead of an LlmpEventManager - since fuzzbench is single threaded.
|
||||||
|
Real fuzz campaigns should consider using multithreaded LlmpEventManager, see the other examples.
|
||||||
|
|
||||||
|
## Build
|
||||||
|
|
||||||
|
To build this example, run `cargo build --release`.
|
||||||
|
This will build the fuzzer compilers (`libafl_cc` and `libafl_cpp`) with `src/lib.rs` as fuzzer.
|
||||||
|
The fuzzer uses the libfuzzer compatibility layer and the SanitizerCoverage runtime functions for coverage feedback.
|
||||||
|
|
||||||
|
These can then be used to build libfuzzer harnesses in the software project of your choice.
|
||||||
|
Finally, just run the resulting binary with `out_dir`, `in_dir`.
|
||||||
|
|
||||||
|
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).
|
||||||
|
|
9
fuzzers/fuzzbench/build.rs
Normal file
9
fuzzers/fuzzbench/build.rs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
// build.rs
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
cc::Build::new()
|
||||||
|
.file("src/libafl_wrapper.c")
|
||||||
|
.compile("libafl_sys.a");
|
||||||
|
println!("cargo:rerun-if-changed=build.rs");
|
||||||
|
println!("cargo:rerun-if-changed=src/libafl_wrapper.c");
|
||||||
|
}
|
15
fuzzers/fuzzbench/fuzz.c
Normal file
15
fuzzers/fuzzbench/fuzz.c
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
|
||||||
|
if (Size >= 8 && *(uint32_t*)Data == 0xaabbccdd)
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
int main() {
|
||||||
|
|
||||||
|
char buf [10] = {0};
|
||||||
|
LLVMFuzzerTestOneInput(buf, 10);
|
||||||
|
|
||||||
|
}*/
|
34
fuzzers/fuzzbench/src/bin/libafl_cc.rs
Normal file
34
fuzzers/fuzzbench/src/bin/libafl_cc.rs
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
use libafl_cc::{ClangWrapper, CompilerWrapper};
|
||||||
|
use std::env;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let args: Vec<String> = env::args().collect();
|
||||||
|
if args.len() > 1 {
|
||||||
|
let mut dir = env::current_exe().unwrap();
|
||||||
|
let wrapper_name = dir.file_name().unwrap().to_str().unwrap();
|
||||||
|
|
||||||
|
let is_cpp = match wrapper_name[wrapper_name.len()-2..].to_lowercase().as_str() {
|
||||||
|
"cc" => false,
|
||||||
|
"++" | "pp" | "xx" => true,
|
||||||
|
_ => panic!("Could not figure out if c or c++ warpper was called. Expected {:?} to end with c or cxx", dir),
|
||||||
|
};
|
||||||
|
|
||||||
|
dir.pop();
|
||||||
|
|
||||||
|
let mut cc = ClangWrapper::new("clang", if is_cpp { "clang++" } else { "clang" });
|
||||||
|
|
||||||
|
cc.is_cpp(is_cpp)
|
||||||
|
.from_args(&args)
|
||||||
|
.unwrap()
|
||||||
|
.link_staticlib(&dir, "fuzzbench".into())
|
||||||
|
.unwrap()
|
||||||
|
.add_arg("-fsanitize-coverage=trace-pc-guard,trace-cmp".into())
|
||||||
|
.unwrap()
|
||||||
|
// silence the compiler wrapper output, needed for some configure scripts.
|
||||||
|
.silence()
|
||||||
|
.run()
|
||||||
|
.unwrap();
|
||||||
|
} else {
|
||||||
|
panic!("LibAFL CC: No Arguments given");
|
||||||
|
}
|
||||||
|
}
|
314
fuzzers/fuzzbench/src/lib.rs
Normal file
314
fuzzers/fuzzbench/src/lib.rs
Normal file
@ -0,0 +1,314 @@
|
|||||||
|
//! A singlethreade libfuzzer-like fuzzer that can auto-restart.
|
||||||
|
|
||||||
|
use clap::{App, Arg};
|
||||||
|
use core::{cell::RefCell, time::Duration};
|
||||||
|
#[cfg(unix)]
|
||||||
|
use nix::{self, unistd::dup};
|
||||||
|
#[cfg(unix)]
|
||||||
|
use std::os::unix::io::{AsRawFd, FromRawFd};
|
||||||
|
use std::{
|
||||||
|
env,
|
||||||
|
fs::{File, OpenOptions},
|
||||||
|
io,
|
||||||
|
io::Write,
|
||||||
|
path::PathBuf,
|
||||||
|
};
|
||||||
|
|
||||||
|
use libafl::{
|
||||||
|
bolts::{
|
||||||
|
current_nanos, current_time,
|
||||||
|
os::dup2,
|
||||||
|
rands::StdRand,
|
||||||
|
shmem::{ShMemProvider, StdShMemProvider},
|
||||||
|
tuples::{tuple_list, Merge},
|
||||||
|
},
|
||||||
|
corpus::{Corpus, IndexesLenTimeMinimizerCorpusScheduler, OnDiskCorpus, QueueCorpusScheduler},
|
||||||
|
events::SimpleRestartingEventManager,
|
||||||
|
executors::{inprocess::InProcessExecutor, ExitKind, TimeoutExecutor},
|
||||||
|
feedback_or,
|
||||||
|
feedbacks::{CrashFeedback, MapFeedbackState, MaxMapFeedback, TimeFeedback, TimeoutFeedback},
|
||||||
|
fuzzer::{Fuzzer, StdFuzzer},
|
||||||
|
inputs::{BytesInput, HasTargetBytes},
|
||||||
|
mutators::{
|
||||||
|
scheduled::{havoc_mutations, StdScheduledMutator},
|
||||||
|
token_mutations::I2SRandReplace,
|
||||||
|
tokens_mutations, Tokens,
|
||||||
|
},
|
||||||
|
observers::{StdMapObserver, TimeObserver},
|
||||||
|
stages::{StdMutationalStage, TracingStage},
|
||||||
|
state::{HasCorpus, HasMetadata, StdState},
|
||||||
|
stats::SimpleStats,
|
||||||
|
Error,
|
||||||
|
};
|
||||||
|
use libafl_targets::{
|
||||||
|
libfuzzer_initialize, libfuzzer_test_one_input, CmpLogObserver, CMPLOG_MAP, EDGES_MAP,
|
||||||
|
MAX_EDGES_NUM,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// The fuzzer main (as `no_mangle` c function)
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn fuzzer_main() {
|
||||||
|
// Registry the metadata types used in this fuzzer
|
||||||
|
// Needed only on no_std
|
||||||
|
//RegistryBuilder::register::<Tokens>();
|
||||||
|
|
||||||
|
let res = App::new("libafl_fuzzbench")
|
||||||
|
.version("0.4.0")
|
||||||
|
.author("AFLplusplus team")
|
||||||
|
.about("LibAFL-based fuzzer for Fuzzbench")
|
||||||
|
.arg(
|
||||||
|
Arg::new("out")
|
||||||
|
.about("The directory to place finds in ('corpus')")
|
||||||
|
.required(true)
|
||||||
|
.index(1)
|
||||||
|
.takes_value(true),
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::new("in")
|
||||||
|
.about("The directory to read initial inputs from ('seeds')")
|
||||||
|
.required(true)
|
||||||
|
.index(2)
|
||||||
|
.takes_value(true),
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::new("tokens")
|
||||||
|
.short('x')
|
||||||
|
.long("tokens")
|
||||||
|
.about("A file to read tokens from, to be used during fuzzing")
|
||||||
|
.takes_value(true),
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::new("logfile")
|
||||||
|
.short('l')
|
||||||
|
.long("logfile")
|
||||||
|
.about("Duplicates all output to this file")
|
||||||
|
.default_value("libafl.log"),
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::new("timeout")
|
||||||
|
.short('t')
|
||||||
|
.long("timeout")
|
||||||
|
.about("Timeout for each individual execution, in milliseconds")
|
||||||
|
.default_value("1000"),
|
||||||
|
)
|
||||||
|
.get_matches();
|
||||||
|
|
||||||
|
println!(
|
||||||
|
"Workdir: {:?}",
|
||||||
|
env::current_dir().unwrap().to_string_lossy().to_string()
|
||||||
|
);
|
||||||
|
|
||||||
|
// For fuzzbench, crashes and finds are inside the same `corpus` directory, in the "queue" and "crashes" subdir.
|
||||||
|
let mut corpus = PathBuf::from(res.value_of("corpus").unwrap().to_string());
|
||||||
|
let mut crashes = corpus.clone();
|
||||||
|
crashes.push("crashes");
|
||||||
|
corpus.push("queue");
|
||||||
|
|
||||||
|
let seeds = PathBuf::from(res.value_of("seeds").unwrap().to_string());
|
||||||
|
|
||||||
|
let tokens = res.value_of("tokens").map(PathBuf::from);
|
||||||
|
|
||||||
|
let logfile = PathBuf::from(res.value_of("logfile").unwrap().to_string());
|
||||||
|
|
||||||
|
let timeout = Duration::from_millis(
|
||||||
|
res.value_of("timeout")
|
||||||
|
.unwrap()
|
||||||
|
.to_string()
|
||||||
|
.parse()
|
||||||
|
.expect("Could not parse timeout in milliseconds"),
|
||||||
|
);
|
||||||
|
|
||||||
|
fuzz(corpus, crashes, seeds, tokens, logfile, timeout)
|
||||||
|
.expect("An error occurred while fuzzing");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The actual fuzzer
|
||||||
|
fn fuzz(
|
||||||
|
corpus_dir: PathBuf,
|
||||||
|
objective_dir: PathBuf,
|
||||||
|
seed_dir: PathBuf,
|
||||||
|
tokenfile: Option<PathBuf>,
|
||||||
|
logfile: PathBuf,
|
||||||
|
timeout: Duration,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
let log = RefCell::new(
|
||||||
|
OpenOptions::new()
|
||||||
|
.append(true)
|
||||||
|
.create(true)
|
||||||
|
.open(&logfile)?,
|
||||||
|
);
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
let mut stdout_cpy = unsafe {
|
||||||
|
let new_fd = dup(io::stdout().as_raw_fd())?;
|
||||||
|
File::from_raw_fd(new_fd)
|
||||||
|
};
|
||||||
|
#[cfg(unix)]
|
||||||
|
let file_null = File::open("/dev/null")?;
|
||||||
|
|
||||||
|
// 'While the stats are state, they are usually used in the broker - which is likely never restarted
|
||||||
|
let stats = SimpleStats::new(|s| {
|
||||||
|
#[cfg(unix)]
|
||||||
|
writeln!(&mut stdout_cpy, "{}", s).unwrap();
|
||||||
|
#[cfg(windows)]
|
||||||
|
println!("{}", s);
|
||||||
|
writeln!(log.borrow_mut(), "{:?} {}", current_time(), s).unwrap();
|
||||||
|
});
|
||||||
|
|
||||||
|
// We need a shared map to store our state before a crash.
|
||||||
|
// This way, we are able to continue fuzzing afterwards.
|
||||||
|
#[cfg(target_os = "android")]
|
||||||
|
AshmemService::start().expect("Failed to start Ashmem service");
|
||||||
|
let mut shmem_provider = StdShMemProvider::new()?;
|
||||||
|
|
||||||
|
let (state, mut mgr) = match SimpleRestartingEventManager::launch(stats, &mut shmem_provider) {
|
||||||
|
// The restarting state will spawn the same process again as child, then restarted it each time it crashes.
|
||||||
|
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
|
||||||
|
// We don't use the hitcounts (see the Cargo.toml, we use pcguard_edges)
|
||||||
|
let edges = unsafe { &mut EDGES_MAP[0..MAX_EDGES_NUM] };
|
||||||
|
let edges_observer = StdMapObserver::new("edges", edges);
|
||||||
|
|
||||||
|
// Create an observation channel to keep track of the execution 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.
|
||||||
|
let feedback_state = MapFeedbackState::with_observer(&edges_observer);
|
||||||
|
|
||||||
|
// Feedback to rate the interestingness of an input
|
||||||
|
// This one is composed by two Feedbacks in OR
|
||||||
|
let feedback = feedback_or!(
|
||||||
|
// New maximization map feedback linked to the edges observer and the feedback state
|
||||||
|
MaxMapFeedback::new_tracking(&feedback_state, &edges_observer, true, false),
|
||||||
|
// Time feedback, this one does not need a feedback state
|
||||||
|
TimeFeedback::new_with_observer(&time_observer)
|
||||||
|
);
|
||||||
|
|
||||||
|
// A feedback to choose if an input is a solution or not
|
||||||
|
let objective = feedback_or!(CrashFeedback::new(), TimeoutFeedback::new());
|
||||||
|
|
||||||
|
// If not restarting, create a State from scratch
|
||||||
|
let mut state = state.unwrap_or_else(|| {
|
||||||
|
StdState::new(
|
||||||
|
// RNG
|
||||||
|
StdRand::with_seed(current_nanos()),
|
||||||
|
// Corpus that will be evolved, we keep it in memory for performance
|
||||||
|
OnDiskCorpus::new(corpus_dir).unwrap(),
|
||||||
|
// 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(),
|
||||||
|
// States of the feedbacks.
|
||||||
|
// They are the data related to the feedbacks that you want to persist in the State.
|
||||||
|
tuple_list!(feedback_state),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
println!("Let's fuzz :)");
|
||||||
|
|
||||||
|
// The actual target run starts here.
|
||||||
|
// Call LLVMFUzzerInitialize() if present.
|
||||||
|
// let args: Vec<String> = env::args().collect();
|
||||||
|
let args = [];
|
||||||
|
if libfuzzer_initialize(&args) == -1 {
|
||||||
|
println!("Warning: LLVMFuzzerInitialize failed with -1")
|
||||||
|
}
|
||||||
|
|
||||||
|
// A minimization+queue policy to get testcasess from the corpus
|
||||||
|
let scheduler = IndexesLenTimeMinimizerCorpusScheduler::new(QueueCorpusScheduler::new());
|
||||||
|
|
||||||
|
// A fuzzer with feedbacks and a corpus scheduler
|
||||||
|
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
|
||||||
|
|
||||||
|
// The wrapped harness function, calling out to the LLVM-style harness
|
||||||
|
let mut harness = |input: &BytesInput| {
|
||||||
|
let target = input.target_bytes();
|
||||||
|
let buf = target.as_slice();
|
||||||
|
libfuzzer_test_one_input(buf);
|
||||||
|
ExitKind::Ok
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut tracing_harness = harness;
|
||||||
|
|
||||||
|
// Create the executor for an in-process function with one observer for edge coverage and one for the execution time
|
||||||
|
let mut executor = TimeoutExecutor::new(
|
||||||
|
InProcessExecutor::new(
|
||||||
|
&mut harness,
|
||||||
|
tuple_list!(edges_observer, time_observer),
|
||||||
|
&mut fuzzer,
|
||||||
|
&mut state,
|
||||||
|
&mut mgr,
|
||||||
|
)?,
|
||||||
|
timeout,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Setup a tracing stage in which we log comparisons
|
||||||
|
let tracing = TracingStage::new(TimeoutExecutor::new(
|
||||||
|
InProcessExecutor::new(
|
||||||
|
&mut tracing_harness,
|
||||||
|
tuple_list!(cmplog_observer),
|
||||||
|
&mut fuzzer,
|
||||||
|
&mut state,
|
||||||
|
&mut mgr,
|
||||||
|
)?,
|
||||||
|
// Give it more time!
|
||||||
|
timeout * 10,
|
||||||
|
));
|
||||||
|
|
||||||
|
// 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().merge(tokens_mutations()));
|
||||||
|
let mutational = StdMutationalStage::new(mutator);
|
||||||
|
|
||||||
|
// The order of the stages matter!
|
||||||
|
let mut stages = tuple_list!(tracing, i2s, mutational);
|
||||||
|
|
||||||
|
// Read tokens
|
||||||
|
if let Some(tokenfile) = tokenfile {
|
||||||
|
if state.metadata().get::<Tokens>().is_none() {
|
||||||
|
state.add_metadata(Tokens::from_tokens_file(tokenfile)?);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// In case the corpus is empty (on first run), reset
|
||||||
|
if state.corpus().count() < 1 {
|
||||||
|
state
|
||||||
|
.load_initial_inputs(&mut fuzzer, &mut executor, &mut mgr, &[seed_dir.clone()])
|
||||||
|
.unwrap_or_else(|_| panic!("Failed to load initial corpus at {:?}", &seed_dir));
|
||||||
|
println!("We imported {} inputs from disk.", state.corpus().count());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove target ouput (logs still survive)
|
||||||
|
#[cfg(unix)]
|
||||||
|
{
|
||||||
|
let null_fd = file_null.as_raw_fd();
|
||||||
|
dup2(null_fd, io::stdout().as_raw_fd())?;
|
||||||
|
dup2(null_fd, io::stderr().as_raw_fd())?;
|
||||||
|
}
|
||||||
|
// reopen file to make sure we're at the end
|
||||||
|
log.replace(
|
||||||
|
OpenOptions::new()
|
||||||
|
.append(true)
|
||||||
|
.create(true)
|
||||||
|
.open(&logfile)?,
|
||||||
|
);
|
||||||
|
|
||||||
|
fuzzer.fuzz_loop(&mut stages, &mut executor, &mut state, &mut mgr)?;
|
||||||
|
|
||||||
|
// Never reached
|
||||||
|
Ok(())
|
||||||
|
}
|
24
fuzzers/fuzzbench/src/libafl_wrapper.c
Normal file
24
fuzzers/fuzzbench/src/libafl_wrapper.c
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
// We only want to link our fuzzer main, if the target doesn't specify its own main - hence we define `main` as `weak` in this file.
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
// jump to rust
|
||||||
|
void fuzzer_main();
|
||||||
|
|
||||||
|
// Link in a dummy llvm test to non-fuzzing builds, for configure et al.
|
||||||
|
int __attribute__((weak)) LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) {
|
||||||
|
(void) buf;
|
||||||
|
(void) len;
|
||||||
|
fprintf(stderr, "LibAFL - No LLVMFuzzerTestOneInput function found! Linker error?\n");
|
||||||
|
fflush(stderr);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
int __attribute__((weak)) main(int argc, char *argv[]) {
|
||||||
|
(void) argc;
|
||||||
|
(void) argv;
|
||||||
|
fuzzer_main();
|
||||||
|
return 0;
|
||||||
|
}
|
@ -33,9 +33,10 @@ args:
|
|||||||
about: "Set the execution timeout in milliseconds, default 10000"
|
about: "Set the execution timeout in milliseconds, default 10000"
|
||||||
value_name: TIMEOUT
|
value_name: TIMEOUT
|
||||||
takes_value: true
|
takes_value: true
|
||||||
- dict:
|
- tokens:
|
||||||
long: dict
|
long: tokens
|
||||||
about: "Feed the fuzzer with an user-specified dictionary of tokens"
|
short: x
|
||||||
|
about: "Feed the fuzzer with an user-specified list of tokens (often called \"dictionary\")"
|
||||||
value_name: DICT
|
value_name: DICT
|
||||||
multiple: true
|
multiple: true
|
||||||
takes_value: true
|
takes_value: true
|
||||||
|
@ -66,8 +66,8 @@ pub fn main() {
|
|||||||
.value_of("output")
|
.value_of("output")
|
||||||
.map(|s| PathBuf::from(s))
|
.map(|s| PathBuf::from(s))
|
||||||
.unwrap_or(workdir.clone());
|
.unwrap_or(workdir.clone());
|
||||||
let dicts: Vec<&str> = matches
|
let token_files: Vec<&str> = matches
|
||||||
.values_of("dict")
|
.values_of("tokens")
|
||||||
.map(|v| v.collect())
|
.map(|v| v.collect())
|
||||||
.unwrap_or(vec![]);
|
.unwrap_or(vec![]);
|
||||||
let timeout_ms = matches
|
let timeout_ms = matches
|
||||||
@ -129,8 +129,8 @@ pub fn main() {
|
|||||||
|
|
||||||
// Create a PNG dictionary if not existing
|
// Create a PNG dictionary if not existing
|
||||||
if state.metadata().get::<Tokens>().is_none() {
|
if state.metadata().get::<Tokens>().is_none() {
|
||||||
for dict in &dicts {
|
for tokens_file in &token_files {
|
||||||
state.add_metadata(Tokens::from_tokens_file(dict)?);
|
state.add_metadata(Tokens::from_tokens_file(tokens_file)?);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ const HASH_CONST: u64 = 0xa5b35705;
|
|||||||
/// The standard rand implementation for `LibAFL`.
|
/// The standard rand implementation for `LibAFL`.
|
||||||
/// It is usually the right choice, with very good speed and a reasonable randomness.
|
/// It is usually the right choice, with very good speed and a reasonable randomness.
|
||||||
/// Not cryptographically secure (which is not what you want during fuzzing ;) )
|
/// Not cryptographically secure (which is not what you want during fuzzing ;) )
|
||||||
pub type StdRand = RomuTrioRand;
|
pub type StdRand = RomuDuoJrRand;
|
||||||
|
|
||||||
/// Ways to get random around here
|
/// Ways to get random around here
|
||||||
/// Please note that these are not cryptographically secure
|
/// Please note that these are not cryptographically secure
|
||||||
|
@ -8,8 +8,6 @@ use core::{
|
|||||||
};
|
};
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
use serde::{de::DeserializeOwned, Serialize};
|
use serde::{de::DeserializeOwned, Serialize};
|
||||||
#[cfg(feature = "std")]
|
|
||||||
use typed_builder::TypedBuilder;
|
|
||||||
|
|
||||||
#[cfg(all(feature = "std", windows))]
|
#[cfg(all(feature = "std", windows))]
|
||||||
use crate::bolts::os::startable_self;
|
use crate::bolts::os::startable_self;
|
||||||
@ -203,7 +201,6 @@ where
|
|||||||
/// `restarter` will start a new process each time the child crashes or times out.
|
/// `restarter` will start a new process each time the child crashes or times out.
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
#[allow(clippy::default_trait_access)]
|
#[allow(clippy::default_trait_access)]
|
||||||
#[derive(TypedBuilder, Debug)]
|
|
||||||
pub struct SimpleRestartingEventManager<I, S, SP, ST>
|
pub struct SimpleRestartingEventManager<I, S, SP, ST>
|
||||||
where
|
where
|
||||||
I: Input,
|
I: Input,
|
||||||
@ -213,16 +210,9 @@ where
|
|||||||
{
|
{
|
||||||
/// The actual simple event mgr
|
/// The actual simple event mgr
|
||||||
simple_event_mgr: SimpleEventManager<I, ST>,
|
simple_event_mgr: SimpleEventManager<I, ST>,
|
||||||
/// The shared memory provider to use for the broker or client spawned by the restarting
|
|
||||||
/// manager.
|
|
||||||
shmem_provider: SP,
|
|
||||||
/// The stats to use
|
|
||||||
#[builder(setter(strip_option))]
|
|
||||||
stats: Option<ST>,
|
|
||||||
/// [`LlmpSender`] for restarts
|
/// [`LlmpSender`] for restarts
|
||||||
sender: LlmpSender<SP>,
|
sender: LlmpSender<SP>,
|
||||||
/// Phantom data
|
/// Phantom data
|
||||||
#[builder(setter(skip), default = PhantomData {})]
|
|
||||||
_phantom: PhantomData<(I, S)>,
|
_phantom: PhantomData<(I, S)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -281,26 +271,6 @@ where
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
|
||||||
impl<I, S, SP, ST> SimpleRestartingEventManager<I, S, SP, ST>
|
|
||||||
where
|
|
||||||
I: Input,
|
|
||||||
S: Serialize,
|
|
||||||
SP: ShMemProvider,
|
|
||||||
ST: Stats, //TODO CE: CustomEvent,
|
|
||||||
{
|
|
||||||
/// Creates a new [`SimpleEventManager`].
|
|
||||||
pub fn new(stats: ST, sender: LlmpSender<SP>, shmem_provider: SP) -> Self {
|
|
||||||
Self {
|
|
||||||
stats: None,
|
|
||||||
sender,
|
|
||||||
simple_event_mgr: SimpleEventManager::new(stats),
|
|
||||||
shmem_provider,
|
|
||||||
_phantom: PhantomData {},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
#[allow(clippy::type_complexity, clippy::too_many_lines)]
|
#[allow(clippy::type_complexity, clippy::too_many_lines)]
|
||||||
impl<I, S, SP, ST> SimpleRestartingEventManager<I, S, SP, ST>
|
impl<I, S, SP, ST> SimpleRestartingEventManager<I, S, SP, ST>
|
||||||
@ -308,24 +278,32 @@ where
|
|||||||
I: Input,
|
I: Input,
|
||||||
S: DeserializeOwned + Serialize,
|
S: DeserializeOwned + Serialize,
|
||||||
SP: ShMemProvider,
|
SP: ShMemProvider,
|
||||||
ST: Stats + Clone,
|
ST: Stats, //TODO CE: CustomEvent,
|
||||||
{
|
{
|
||||||
/// Launch the restarting manager
|
/// Creates a new [`SimpleEventManager`].
|
||||||
|
fn new_launched(stats: ST, sender: LlmpSender<SP>) -> Self {
|
||||||
|
Self {
|
||||||
|
sender,
|
||||||
|
simple_event_mgr: SimpleEventManager::new(stats),
|
||||||
|
_phantom: PhantomData {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Launch the simple restarting manager.
|
||||||
|
/// This [`EventManager`] is simple and single threaded,
|
||||||
|
/// but can still used shared maps to recover from crashes and timeouts.
|
||||||
|
#[allow(clippy::similar_names)]
|
||||||
pub fn launch(
|
pub fn launch(
|
||||||
&mut self,
|
stats: ST,
|
||||||
|
shmem_provider: &mut SP,
|
||||||
) -> Result<(Option<S>, SimpleRestartingEventManager<I, S, SP, ST>), Error> {
|
) -> Result<(Option<S>, SimpleRestartingEventManager<I, S, SP, ST>), Error> {
|
||||||
// We start ourself as child process to actually fuzz
|
// We start ourself as child process to actually fuzz
|
||||||
let (mut sender, mut receiver, new_shmem_provider) = if std::env::var(_ENV_FUZZER_SENDER)
|
let (mut sender, mut receiver) = if std::env::var(_ENV_FUZZER_SENDER).is_err() {
|
||||||
.is_err()
|
|
||||||
{
|
|
||||||
// First, create a channel from the fuzzer (sender) to us (receiver) to report its state for restarts.
|
// First, create a channel from the fuzzer (sender) to us (receiver) to report its state for restarts.
|
||||||
let sender = { LlmpSender::new(self.shmem_provider.clone(), 0, false)? };
|
let sender = { LlmpSender::new(shmem_provider.clone(), 0, false)? };
|
||||||
|
|
||||||
let map = {
|
let map = { shmem_provider.clone_ref(&sender.out_maps.last().unwrap().shmem)? };
|
||||||
self.shmem_provider
|
let receiver = LlmpReceiver::on_existing_map(shmem_provider.clone(), map, None)?;
|
||||||
.clone_ref(&sender.out_maps.last().unwrap().shmem)?
|
|
||||||
};
|
|
||||||
let receiver = LlmpReceiver::on_existing_map(self.shmem_provider.clone(), map, None)?;
|
|
||||||
// Store the information to a map.
|
// Store the information to a map.
|
||||||
sender.to_env(_ENV_FUZZER_SENDER)?;
|
sender.to_env(_ENV_FUZZER_SENDER)?;
|
||||||
receiver.to_env(_ENV_FUZZER_RECEIVER)?;
|
receiver.to_env(_ENV_FUZZER_RECEIVER)?;
|
||||||
@ -338,15 +316,15 @@ where
|
|||||||
// On Unix, we fork
|
// On Unix, we fork
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
let child_status = {
|
let child_status = {
|
||||||
self.shmem_provider.pre_fork()?;
|
shmem_provider.pre_fork()?;
|
||||||
match unsafe { fork() }? {
|
match unsafe { fork() }? {
|
||||||
ForkResult::Parent(handle) => {
|
ForkResult::Parent(handle) => {
|
||||||
self.shmem_provider.post_fork(false)?;
|
shmem_provider.post_fork(false)?;
|
||||||
handle.status()
|
handle.status()
|
||||||
}
|
}
|
||||||
ForkResult::Child => {
|
ForkResult::Child => {
|
||||||
self.shmem_provider.post_fork(true)?;
|
shmem_provider.post_fork(true)?;
|
||||||
break (sender, receiver, self.shmem_provider.clone());
|
break (sender, receiver);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -376,12 +354,8 @@ where
|
|||||||
// We get here *only on Windows*, if we were started by a restarting fuzzer.
|
// We get here *only on Windows*, if we were started by a restarting fuzzer.
|
||||||
// A sender and a receiver for single communication
|
// A sender and a receiver for single communication
|
||||||
(
|
(
|
||||||
LlmpSender::on_existing_from_env(self.shmem_provider.clone(), _ENV_FUZZER_SENDER)?,
|
LlmpSender::on_existing_from_env(shmem_provider.clone(), _ENV_FUZZER_SENDER)?,
|
||||||
LlmpReceiver::on_existing_from_env(
|
LlmpReceiver::on_existing_from_env(shmem_provider.clone(), _ENV_FUZZER_RECEIVER)?,
|
||||||
self.shmem_provider.clone(),
|
|
||||||
_ENV_FUZZER_RECEIVER,
|
|
||||||
)?,
|
|
||||||
self.shmem_provider.clone(),
|
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -394,11 +368,7 @@ where
|
|||||||
// Mgr to send and receive msgs from/to all other fuzzer instances
|
// Mgr to send and receive msgs from/to all other fuzzer instances
|
||||||
(
|
(
|
||||||
None,
|
None,
|
||||||
SimpleRestartingEventManager::new(
|
SimpleRestartingEventManager::new_launched(stats, sender),
|
||||||
self.stats.take().unwrap(),
|
|
||||||
sender,
|
|
||||||
new_shmem_provider,
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
// Restoring from a previous run, deserialize state and corpus.
|
// Restoring from a previous run, deserialize state and corpus.
|
||||||
@ -412,11 +382,7 @@ where
|
|||||||
|
|
||||||
(
|
(
|
||||||
Some(state),
|
Some(state),
|
||||||
SimpleRestartingEventManager::new(
|
SimpleRestartingEventManager::new_launched(stats, sender),
|
||||||
self.stats.take().unwrap(),
|
|
||||||
sender,
|
|
||||||
new_shmem_provider,
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -206,7 +206,7 @@ impl Forkserver {
|
|||||||
Ok(_) => {}
|
Ok(_) => {}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
return Err(Error::Forkserver(format!(
|
return Err(Error::Forkserver(format!(
|
||||||
"Could not spawn forkserver: {:#?}",
|
"Could not spawn the forkserver: {:#?}",
|
||||||
err
|
err
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
@ -460,7 +460,8 @@ where
|
|||||||
stats_timeout: Duration,
|
stats_timeout: Duration,
|
||||||
) -> Result<Duration, Error> {
|
) -> Result<Duration, Error> {
|
||||||
let cur = current_time();
|
let cur = current_time();
|
||||||
if cur - last > stats_timeout {
|
// default to 0 here to avoid crashes on clock skew
|
||||||
|
if cur.checked_sub(last).unwrap_or_default() > stats_timeout {
|
||||||
// Default no introspection implmentation
|
// Default no introspection implmentation
|
||||||
#[cfg(not(feature = "introspection"))]
|
#[cfg(not(feature = "introspection"))]
|
||||||
manager.fire(
|
manager.fire(
|
||||||
|
@ -19,6 +19,12 @@ use crate::bolts::current_time;
|
|||||||
|
|
||||||
const CLIENT_STATS_TIME_WINDOW_SECS: u64 = 5; // 5 seconds
|
const CLIENT_STATS_TIME_WINDOW_SECS: u64 = 5; // 5 seconds
|
||||||
|
|
||||||
|
/// Number of stages in the fuzzer
|
||||||
|
pub(crate) const NUM_STAGES: usize = 8;
|
||||||
|
|
||||||
|
/// Number of feedback mechanisms to measure for performance
|
||||||
|
pub(crate) const NUM_FEEDBACKS: usize = 16;
|
||||||
|
|
||||||
/// User-defined stats types
|
/// User-defined stats types
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
pub enum UserStats {
|
pub enum UserStats {
|
||||||
@ -224,6 +230,7 @@ impl Stats for NopStats {
|
|||||||
|
|
||||||
impl NopStats {
|
impl NopStats {
|
||||||
/// Create new [`NopStats`]
|
/// Create new [`NopStats`]
|
||||||
|
#[must_use]
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
start_time: current_time(),
|
start_time: current_time(),
|
||||||
@ -350,12 +357,6 @@ macro_rules! mark_feedback_time {
|
|||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Number of stages in the fuzzer
|
|
||||||
pub(crate) const NUM_STAGES: usize = 8;
|
|
||||||
|
|
||||||
/// Number of feedback mechanisms to measure for performance
|
|
||||||
pub(crate) const NUM_FEEDBACKS: usize = 16;
|
|
||||||
|
|
||||||
/// Client performance statistics
|
/// Client performance statistics
|
||||||
#[derive(Serialize, Deserialize, Debug, Copy, Clone)]
|
#[derive(Serialize, Deserialize, Debug, Copy, Clone)]
|
||||||
pub struct ClientPerfStats {
|
pub struct ClientPerfStats {
|
||||||
@ -770,6 +771,7 @@ impl core::fmt::Display for ClientPerfStats {
|
|||||||
|
|
||||||
#[cfg(feature = "introspection")]
|
#[cfg(feature = "introspection")]
|
||||||
impl Default for ClientPerfStats {
|
impl Default for ClientPerfStats {
|
||||||
|
#[must_use]
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self::new()
|
Self::new()
|
||||||
}
|
}
|
||||||
|
@ -51,10 +51,19 @@ pub trait CompilerWrapper {
|
|||||||
/// Get if in linking mode
|
/// Get if in linking mode
|
||||||
fn is_linking(&self) -> bool;
|
fn is_linking(&self) -> bool;
|
||||||
|
|
||||||
|
/// Silences `libafl_cc` output
|
||||||
|
fn silence(&mut self) -> &'_ mut Self;
|
||||||
|
|
||||||
|
/// Returns `true` if `silence` was called
|
||||||
|
fn is_silent(&self) -> bool;
|
||||||
|
|
||||||
/// Run the compiler
|
/// Run the compiler
|
||||||
fn run(&mut self) -> Result<(), Error> {
|
fn run(&mut self) -> Result<(), Error> {
|
||||||
let args = self.command()?;
|
let args = self.command()?;
|
||||||
dbg!(&args);
|
|
||||||
|
if !self.is_silent() {
|
||||||
|
dbg!(&args);
|
||||||
|
}
|
||||||
if args.is_empty() {
|
if args.is_empty() {
|
||||||
return Err(Error::InvalidArguments(
|
return Err(Error::InvalidArguments(
|
||||||
"The number of arguments cannot be 0".into(),
|
"The number of arguments cannot be 0".into(),
|
||||||
@ -64,7 +73,9 @@ pub trait CompilerWrapper {
|
|||||||
Ok(s) => s,
|
Ok(s) => s,
|
||||||
Err(e) => return Err(Error::Io(e)),
|
Err(e) => return Err(Error::Io(e)),
|
||||||
};
|
};
|
||||||
dbg!(status);
|
if !self.is_silent() {
|
||||||
|
dbg!(status);
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -72,6 +83,7 @@ pub trait CompilerWrapper {
|
|||||||
/// Wrap Clang
|
/// Wrap Clang
|
||||||
#[allow(clippy::struct_excessive_bools)]
|
#[allow(clippy::struct_excessive_bools)]
|
||||||
pub struct ClangWrapper {
|
pub struct ClangWrapper {
|
||||||
|
is_silent: bool,
|
||||||
optimize: bool,
|
optimize: bool,
|
||||||
wrapped_cc: String,
|
wrapped_cc: String,
|
||||||
wrapped_cxx: String,
|
wrapped_cxx: String,
|
||||||
@ -167,13 +179,21 @@ impl CompilerWrapper for ClangWrapper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn link_staticlib(&mut self, dir: &Path, name: String) -> Result<&'_ mut Self, Error> {
|
fn link_staticlib(&mut self, dir: &Path, name: String) -> Result<&'_ mut Self, Error> {
|
||||||
self.add_link_arg("-Wl,--whole-archive".into())?
|
if cfg!(any(target_os = "macos", target_os = "ios")) {
|
||||||
.add_link_arg(
|
//self.add_link_arg("-force_load".into())?;
|
||||||
dir.join(format!("{}{}.{}", LIB_PREFIX, name, LIB_EXT))
|
} else {
|
||||||
.display()
|
self.add_link_arg("-Wl,--whole-archive".into())?;
|
||||||
.to_string(),
|
}
|
||||||
)?
|
self.add_link_arg(
|
||||||
.add_link_arg("-Wl,-no-whole-archive".into())
|
dir.join(format!("{}{}.{}", LIB_PREFIX, name, LIB_EXT))
|
||||||
|
.display()
|
||||||
|
.to_string(),
|
||||||
|
)?;
|
||||||
|
if cfg!(any(target_os = "macos", target_os = "ios")) {
|
||||||
|
Ok(self)
|
||||||
|
} else {
|
||||||
|
self.add_link_arg("-Wl,-no-whole-archive".into())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn command(&mut self) -> Result<Vec<String>, Error> {
|
fn command(&mut self) -> Result<Vec<String>, Error> {
|
||||||
@ -201,6 +221,15 @@ impl CompilerWrapper for ClangWrapper {
|
|||||||
fn is_linking(&self) -> bool {
|
fn is_linking(&self) -> bool {
|
||||||
self.linking
|
self.linking
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn silence(&mut self) -> &'_ mut Self {
|
||||||
|
self.is_silent = true;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_silent(&self) -> bool {
|
||||||
|
self.is_silent
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ClangWrapper {
|
impl ClangWrapper {
|
||||||
@ -219,6 +248,7 @@ impl ClangWrapper {
|
|||||||
base_args: vec![],
|
base_args: vec![],
|
||||||
cc_args: vec![],
|
cc_args: vec![],
|
||||||
link_args: vec![],
|
link_args: vec![],
|
||||||
|
is_silent: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
|
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
|
||||||
cd "$SCRIPT_DIR/.."
|
cd "$SCRIPT_DIR/.."
|
||||||
|
|
||||||
@ -8,11 +9,20 @@ cd fuzzers
|
|||||||
|
|
||||||
for fuzzer in *;
|
for fuzzer in *;
|
||||||
do
|
do
|
||||||
echo "[+] Checking fmt and building $fuzzer"
|
cd $fuzzer
|
||||||
cd $fuzzer \
|
# Clippy checks
|
||||||
&& cargo fmt --all -- --check \
|
if [ "$1" != "--no-fmt" ]; then
|
||||||
&& cargo clippy \
|
|
||||||
&& cargo build \
|
echo "[*] Checking fmt for $fuzzer"
|
||||||
&& cd .. \
|
cargo fmt --all -- --check || exit 1
|
||||||
|| exit 1
|
echo "[*] Running clippy for $fuzzer"
|
||||||
|
cargo clippy || exit 1
|
||||||
|
else
|
||||||
|
echo "[+] Skipping fmt and clippy for $fuzzer (--no-fmt specified)"
|
||||||
|
fi
|
||||||
|
echo "[*] Building $fuzzer"
|
||||||
|
cargo build || exit 1
|
||||||
|
cd ..
|
||||||
|
echo "[+] Done building $fuzzer"
|
||||||
|
echo ""
|
||||||
done
|
done
|
||||||
|
Loading…
x
Reference in New Issue
Block a user