Document libafl_libfuzzer (#1457)
* prep for publishing libafl_libfuzzer * learn to use linkers * document-features * special handling for fuzzbench builds * Update cmplog.c * drop dep for llvm-tools; add testcase for memcmp sanity --------- Co-authored-by: Dongjia "toka" Zhang <tokazerkje@outlook.com>
This commit is contained in:
parent
f7c94f9a85
commit
9aa40c0734
1
.github/workflows/build_and_test.yml
vendored
1
.github/workflows/build_and_test.yml
vendored
@ -114,7 +114,6 @@ jobs:
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: stable
|
||||
components: llvm-tools
|
||||
- name: Install and cache deps
|
||||
uses: awalsh128/cache-apt-pkgs-action@v1.1.0
|
||||
with:
|
||||
|
@ -44,4 +44,3 @@ lto = true
|
||||
codegen-units = 1
|
||||
opt-level = 3
|
||||
debug = true
|
||||
|
||||
|
@ -1,8 +1,14 @@
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
|
||||
if (Size >= 8 && *(uint32_t *)Data == 0xaabbccdd) { abort(); }
|
||||
char buf[8] = {'a', 'b', 'c', 'd'};
|
||||
|
||||
if (memcmp(Data, buf, 4) == 0) {
|
||||
abort();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -16,9 +16,22 @@ cc = "1.0"
|
||||
rustversion = "1.0"
|
||||
|
||||
[features]
|
||||
#! ## Feature Flags
|
||||
|
||||
## enables the derive macros for the arbitrary dependency, transparently forwarded from libfuzzer-sys
|
||||
arbitrary-derive = ["libfuzzer-sys/arbitrary-derive"]
|
||||
## enables fuzzer introspection with LibAFL's `introspection` feature
|
||||
introspection = []
|
||||
whole-archive = []
|
||||
|
||||
[dependencies]
|
||||
libfuzzer-sys = { version = "0.4.7", default-features = false }
|
||||
|
||||
document-features = { version = "0.2" }
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
features = ["document-features"]
|
||||
all-features = true
|
||||
|
||||
rustdoc-args = [
|
||||
"--cfg", "docsrs",
|
||||
]
|
||||
|
@ -1,8 +1,8 @@
|
||||
use std::{path::PathBuf, process::Command};
|
||||
|
||||
fn main() {
|
||||
if cfg!(feature = "cargo-clippy") {
|
||||
return; // skip when clippy is running
|
||||
if cfg!(any(feature = "cargo-clippy", docsrs)) {
|
||||
return; // skip when clippy or docs is running
|
||||
}
|
||||
if cfg!(not(target_os = "linux")) {
|
||||
println!(
|
||||
@ -65,52 +65,11 @@ fn main() {
|
||||
|
||||
let mut lib_path = custom_lib_dir.join(std::env::var_os("TARGET").unwrap());
|
||||
lib_path.push("release");
|
||||
lib_path.push("libafl_libfuzzer_runtime.a");
|
||||
|
||||
// // TODO this is definitely not compat with macOS/Windows...
|
||||
if cfg!(feature = "whole-archive") {
|
||||
use std::path::Path;
|
||||
let target_libdir = Command::new("rustc")
|
||||
.args(["--print", "target-libdir"])
|
||||
.output()
|
||||
.expect("Couldn't find rustc's target-libdir");
|
||||
let target_libdir = String::from_utf8(target_libdir.stdout).unwrap();
|
||||
let target_libdir = Path::new(target_libdir.trim());
|
||||
|
||||
let rust_lld = target_libdir.join("../bin/rust-lld");
|
||||
let rust_ar = target_libdir.join("../bin/llvm-ar"); // NOTE: depends on llvm-tools
|
||||
|
||||
let mut command = Command::new(rust_lld);
|
||||
command
|
||||
.args(["-flavor", "gnu"])
|
||||
.arg("-r")
|
||||
.arg("--whole-archive")
|
||||
.arg(lib_path)
|
||||
.args(["-o", custom_lib_dir.join("libFuzzer.o").to_str().expect("Invalid path characters present in your current directory prevent us from linking to the runtime")]);
|
||||
|
||||
assert!(
|
||||
!command.status().map(|s| !s.success()).unwrap_or(true),
|
||||
"Couldn't link runtime crate! Do you have the llvm-tools component installed?"
|
||||
);
|
||||
|
||||
let mut command = Command::new(rust_ar);
|
||||
command
|
||||
.arg("cr")
|
||||
.arg(custom_lib_dir.join("libFuzzer.a"))
|
||||
.arg(custom_lib_dir.join("libFuzzer.o"));
|
||||
|
||||
assert!(
|
||||
!command.status().map(|s| !s.success()).unwrap_or(true),
|
||||
"Couldn't create runtime archive!"
|
||||
);
|
||||
} else {
|
||||
std::fs::copy(lib_path, custom_lib_dir.join("libFuzzer.a")).unwrap();
|
||||
}
|
||||
|
||||
println!(
|
||||
"cargo:rustc-link-search=native={}",
|
||||
custom_lib_dir.to_str().unwrap()
|
||||
lib_path.to_str().unwrap()
|
||||
);
|
||||
println!("cargo:rustc-link-lib=static=Fuzzer");
|
||||
println!("cargo:rustc-link-lib=static=afl_libfuzzer_runtime");
|
||||
println!("cargo:rustc-link-lib=stdc++");
|
||||
}
|
||||
|
@ -18,6 +18,12 @@ codegen-units = 1
|
||||
opt-level = 3
|
||||
debug = true
|
||||
|
||||
# debug-free release profile for fuzzbench due to space restrictions
|
||||
[profile.release-fuzzbench]
|
||||
inherits = "release"
|
||||
debug = false
|
||||
strip = true
|
||||
|
||||
|
||||
[lib]
|
||||
name = "afl_libfuzzer_runtime" # TODO fix name once cargo-fuzz stops stripping double-prefixes
|
||||
|
@ -27,25 +27,25 @@
|
||||
clippy::unsafe_derive_deserialize
|
||||
)]
|
||||
#![cfg_attr(not(test), warn(
|
||||
missing_debug_implementations,
|
||||
missing_docs,
|
||||
//trivial_casts,
|
||||
trivial_numeric_casts,
|
||||
unused_extern_crates,
|
||||
unused_import_braces,
|
||||
unused_qualifications,
|
||||
//unused_results
|
||||
missing_debug_implementations,
|
||||
missing_docs,
|
||||
//trivial_casts,
|
||||
trivial_numeric_casts,
|
||||
unused_extern_crates,
|
||||
unused_import_braces,
|
||||
unused_qualifications,
|
||||
//unused_results
|
||||
))]
|
||||
#![cfg_attr(test, deny(
|
||||
missing_debug_implementations,
|
||||
missing_docs,
|
||||
//trivial_casts,
|
||||
trivial_numeric_casts,
|
||||
unused_extern_crates,
|
||||
unused_import_braces,
|
||||
unused_qualifications,
|
||||
unused_must_use,
|
||||
//unused_results
|
||||
missing_debug_implementations,
|
||||
missing_docs,
|
||||
//trivial_casts,
|
||||
trivial_numeric_casts,
|
||||
unused_extern_crates,
|
||||
unused_import_braces,
|
||||
unused_qualifications,
|
||||
unused_must_use,
|
||||
//unused_results
|
||||
))]
|
||||
#![cfg_attr(
|
||||
test,
|
||||
|
@ -1,5 +1,68 @@
|
||||
//! `libafl_libfuzzer` offers a "permanent" replacement for the now-deprecated libfuzzer
|
||||
//!
|
||||
//! ## Usage
|
||||
//!
|
||||
//! To use LibAFL in place of libfuzzer, change the following line in your fuzz/Cargo.toml:
|
||||
//!
|
||||
//! ```toml
|
||||
//! libfuzzer-sys = { version = "*", features = [...] }
|
||||
//! ```
|
||||
//!
|
||||
//! With the following:
|
||||
//!
|
||||
//! ```toml
|
||||
//! libfuzzer-sys = { version = "*", features = [...], package = "libafl_libfuzzer" }
|
||||
//! ```
|
||||
//!
|
||||
//! To use bleeding changes from upstream, use the following:
|
||||
//!
|
||||
//! ```toml
|
||||
//! libfuzzer-sys = { version = "*", features = [...], package = "libafl_libfuzzer", git = "https://github.com/AFLplusplus/LibAFL" }
|
||||
//! ```
|
||||
//!
|
||||
//! ## Flags
|
||||
//!
|
||||
//! You can pass additional flags to the libfuzzer runtime in `cargo-fuzz` like so:
|
||||
//!
|
||||
//! ```bash
|
||||
//! cargo fuzz run fuzz_target -- -extra_flag=1
|
||||
//! ```
|
||||
//!
|
||||
//! You will commonly need this for flags such as `-ignore_crashes=1` and `-timeout=5`. In addition
|
||||
//! to partial support of libfuzzer flags, `libafl_libfuzzer` offers:
|
||||
//!
|
||||
//! - `-dedup=n`, with `n` = 1 enabling deduplication of crashes by stacktrace.
|
||||
//! - `-grimoire=n`, with `n` set to 0 or 1 disabling or enabling [grimoire] mutations, respectively.
|
||||
//! - if not specified explicitly, `libafl_libfuzzer` will "guess" which setting is appropriate
|
||||
//! - you should disable grimoire if your target is not string-like
|
||||
//! - `-report=n`, with `n` = 1 causing `libafl_libfuzzer` to emit a report on the corpus content.
|
||||
//! - `-skip_tracing=n`, with `n` = 1 causing `libafl_libfuzzer` to disable comparison log tracing.
|
||||
//! - you should do this if your target performs many comparisons on memory sequences which are
|
||||
//! not contained in the input
|
||||
//! - `-tui=n`, with `n` = 1 enabling a graphical terminal interface.
|
||||
//! - experimental; some users report inconsistent behaviour with tui enabled
|
||||
//!
|
||||
//! [grimoire]: https://www.usenix.org/conference/usenixsecurity19/presentation/blazytko
|
||||
//!
|
||||
//! ### Supported flags from libfuzzer
|
||||
//!
|
||||
//! - `-merge`
|
||||
//! - `-minimize_crash`
|
||||
//! - `-artifact_prefix`
|
||||
//! - `-timeout`
|
||||
//! - unlike libfuzzer, `libafl_libfuzzer` supports partial second timeouts (e.g. `-timeout=.5`)
|
||||
//! - `-dict`
|
||||
//! - `-fork` and `-jobs`
|
||||
//! - in `libafl_libfuzzer`, these are synonymous
|
||||
//! - `-ignore_crashes`, `-ignore_ooms`, and `-ignore_timeouts`
|
||||
//! - `-rss_limit_mb` and `-malloc_limit_mb`
|
||||
//! - `-ignore_remaining_args`
|
||||
//! - `-shrink`
|
||||
//! - `-runs`
|
||||
//! - `-close_fd_mask`
|
||||
//!
|
||||
//! ## Important notes
|
||||
//!
|
||||
//! This crate only offers sufficient functionality to replace libfuzzer for cargo-fuzz in its
|
||||
//! current state, but may be expanded to handle other flags in the future.
|
||||
//!
|
||||
@ -7,12 +70,17 @@
|
||||
//! The internal crate must be built separately to ensure flags from dependent crates are not leaked
|
||||
//! to the runtime (e.g., to prevent coverage being collected on the runtime).
|
||||
|
||||
#![doc = document_features::document_features!()]
|
||||
|
||||
use std::ffi::{c_char, c_int};
|
||||
|
||||
pub use libfuzzer_sys::*;
|
||||
|
||||
extern "C" {
|
||||
/// `LLVMFuzzerRunDriver` allows for harnesses which specify their own main. See: https://llvm.org/docs/LibFuzzer.html#using-libfuzzer-as-a-library
|
||||
/// `LLVMFuzzerRunDriver` allows for harnesses which specify their own main. See: <https://llvm.org/docs/LibFuzzer.html#using-libfuzzer-as-a-library>
|
||||
///
|
||||
/// You can call this function inside of a main function in your harness, or specify `#![no_main]`
|
||||
/// to accept the default runtime driver.
|
||||
pub fn LLVMFuzzerRunDriver(
|
||||
argc: *mut c_int,
|
||||
argv: *mut *mut *const c_char,
|
||||
|
@ -67,6 +67,12 @@ fn main() {
|
||||
#[cfg(feature = "sancov_cmplog")]
|
||||
{
|
||||
sancov_cmp.define("SANCOV_CMPLOG", "1");
|
||||
|
||||
println!("cargo:rustc-link-arg=--undefined=__sanitizer_weak_hook_memcmp");
|
||||
println!("cargo:rustc-link-arg=--undefined=__sanitizer_weak_hook_strncmp");
|
||||
println!("cargo:rustc-link-arg=--undefined=__sanitizer_weak_hook_strncasecmp");
|
||||
println!("cargo:rustc-link-arg=--undefined=__sanitizer_weak_hook_strcmp");
|
||||
println!("cargo:rustc-link-arg=--undefined=__sanitizer_weak_hook_strcasecmp");
|
||||
}
|
||||
|
||||
sancov_cmp
|
||||
@ -75,6 +81,18 @@ fn main() {
|
||||
.define("CMPLOG_MAP_H", Some(&*format!("{cmplog_map_h}")))
|
||||
.file(src_dir.join("sancov_cmp.c"))
|
||||
.compile("sancov_cmp");
|
||||
|
||||
println!("cargo:rustc-link-arg=--undefined=__sanitizer_cov_trace_cmp1");
|
||||
println!("cargo:rustc-link-arg=--undefined=__sanitizer_cov_trace_cmp2");
|
||||
println!("cargo:rustc-link-arg=--undefined=__sanitizer_cov_trace_cmp4");
|
||||
println!("cargo:rustc-link-arg=--undefined=__sanitizer_cov_trace_cmp8");
|
||||
|
||||
println!("cargo:rustc-link-arg=--undefined=__sanitizer_cov_trace_const_cmp1");
|
||||
println!("cargo:rustc-link-arg=--undefined=__sanitizer_cov_trace_const_cmp2");
|
||||
println!("cargo:rustc-link-arg=--undefined=__sanitizer_cov_trace_const_cmp4");
|
||||
println!("cargo:rustc-link-arg=--undefined=__sanitizer_cov_trace_const_cmp8");
|
||||
|
||||
println!("cargo:rustc-link-arg=--undefined=__sanitizer_cov_trace_switch");
|
||||
}
|
||||
|
||||
#[cfg(feature = "libfuzzer")]
|
||||
|
@ -141,7 +141,7 @@ void __libafl_targets_cmplog_routines_len(uintptr_t k, const uint8_t *ptr1,
|
||||
__libafl_targets_cmplog_routines_checked(k, ptr1, ptr2, len);
|
||||
}
|
||||
|
||||
static inline void __cmplog_rtn_hook(const uint8_t *ptr1, const uint8_t *ptr2) {
|
||||
void __cmplog_rtn_hook(const uint8_t *ptr1, const uint8_t *ptr2) {
|
||||
uintptr_t k = RETADDR;
|
||||
k = (k >> 4) ^ (k << 8);
|
||||
k &= CMPLOG_MAP_W - 1;
|
||||
|
@ -70,3 +70,7 @@ fi
|
||||
cd libafl_concolic/symcc_runtime
|
||||
cargo publish "$@"
|
||||
cd ../.. || exit 1
|
||||
|
||||
cd libafl_libfuzzer
|
||||
cargo publish "$@"
|
||||
cd ../.. || exit 1
|
||||
|
Loading…
x
Reference in New Issue
Block a user