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:
|
with:
|
||||||
profile: minimal
|
profile: minimal
|
||||||
toolchain: stable
|
toolchain: stable
|
||||||
components: llvm-tools
|
|
||||||
- name: Install and cache deps
|
- name: Install and cache deps
|
||||||
uses: awalsh128/cache-apt-pkgs-action@v1.1.0
|
uses: awalsh128/cache-apt-pkgs-action@v1.1.0
|
||||||
with:
|
with:
|
||||||
|
@ -44,4 +44,3 @@ lto = true
|
|||||||
codegen-units = 1
|
codegen-units = 1
|
||||||
opt-level = 3
|
opt-level = 3
|
||||||
debug = true
|
debug = true
|
||||||
|
|
||||||
|
@ -1,8 +1,14 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
|
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
|
||||||
if (Size >= 8 && *(uint32_t *)Data == 0xaabbccdd) { abort(); }
|
if (Size >= 8 && *(uint32_t *)Data == 0xaabbccdd) { abort(); }
|
||||||
|
char buf[8] = {'a', 'b', 'c', 'd'};
|
||||||
|
|
||||||
|
if (memcmp(Data, buf, 4) == 0) {
|
||||||
|
abort();
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,9 +16,22 @@ cc = "1.0"
|
|||||||
rustversion = "1.0"
|
rustversion = "1.0"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
|
#! ## Feature Flags
|
||||||
|
|
||||||
|
## enables the derive macros for the arbitrary dependency, transparently forwarded from libfuzzer-sys
|
||||||
arbitrary-derive = ["libfuzzer-sys/arbitrary-derive"]
|
arbitrary-derive = ["libfuzzer-sys/arbitrary-derive"]
|
||||||
|
## enables fuzzer introspection with LibAFL's `introspection` feature
|
||||||
introspection = []
|
introspection = []
|
||||||
whole-archive = []
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
libfuzzer-sys = { version = "0.4.7", default-features = false }
|
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};
|
use std::{path::PathBuf, process::Command};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
if cfg!(feature = "cargo-clippy") {
|
if cfg!(any(feature = "cargo-clippy", docsrs)) {
|
||||||
return; // skip when clippy is running
|
return; // skip when clippy or docs is running
|
||||||
}
|
}
|
||||||
if cfg!(not(target_os = "linux")) {
|
if cfg!(not(target_os = "linux")) {
|
||||||
println!(
|
println!(
|
||||||
@ -65,52 +65,11 @@ fn main() {
|
|||||||
|
|
||||||
let mut lib_path = custom_lib_dir.join(std::env::var_os("TARGET").unwrap());
|
let mut lib_path = custom_lib_dir.join(std::env::var_os("TARGET").unwrap());
|
||||||
lib_path.push("release");
|
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!(
|
println!(
|
||||||
"cargo:rustc-link-search=native={}",
|
"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++");
|
println!("cargo:rustc-link-lib=stdc++");
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,12 @@ codegen-units = 1
|
|||||||
opt-level = 3
|
opt-level = 3
|
||||||
debug = true
|
debug = true
|
||||||
|
|
||||||
|
# debug-free release profile for fuzzbench due to space restrictions
|
||||||
|
[profile.release-fuzzbench]
|
||||||
|
inherits = "release"
|
||||||
|
debug = false
|
||||||
|
strip = true
|
||||||
|
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
name = "afl_libfuzzer_runtime" # TODO fix name once cargo-fuzz stops stripping double-prefixes
|
name = "afl_libfuzzer_runtime" # TODO fix name once cargo-fuzz stops stripping double-prefixes
|
||||||
|
@ -1,5 +1,68 @@
|
|||||||
//! `libafl_libfuzzer` offers a "permanent" replacement for the now-deprecated libfuzzer
|
//! `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
|
//! 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.
|
//! 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
|
//! 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).
|
//! 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};
|
use std::ffi::{c_char, c_int};
|
||||||
|
|
||||||
pub use libfuzzer_sys::*;
|
pub use libfuzzer_sys::*;
|
||||||
|
|
||||||
extern "C" {
|
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(
|
pub fn LLVMFuzzerRunDriver(
|
||||||
argc: *mut c_int,
|
argc: *mut c_int,
|
||||||
argv: *mut *mut *const c_char,
|
argv: *mut *mut *const c_char,
|
||||||
|
@ -67,6 +67,12 @@ fn main() {
|
|||||||
#[cfg(feature = "sancov_cmplog")]
|
#[cfg(feature = "sancov_cmplog")]
|
||||||
{
|
{
|
||||||
sancov_cmp.define("SANCOV_CMPLOG", "1");
|
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
|
sancov_cmp
|
||||||
@ -75,6 +81,18 @@ fn main() {
|
|||||||
.define("CMPLOG_MAP_H", Some(&*format!("{cmplog_map_h}")))
|
.define("CMPLOG_MAP_H", Some(&*format!("{cmplog_map_h}")))
|
||||||
.file(src_dir.join("sancov_cmp.c"))
|
.file(src_dir.join("sancov_cmp.c"))
|
||||||
.compile("sancov_cmp");
|
.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")]
|
#[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);
|
__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;
|
uintptr_t k = RETADDR;
|
||||||
k = (k >> 4) ^ (k << 8);
|
k = (k >> 4) ^ (k << 8);
|
||||||
k &= CMPLOG_MAP_W - 1;
|
k &= CMPLOG_MAP_W - 1;
|
||||||
|
@ -70,3 +70,7 @@ fi
|
|||||||
cd libafl_concolic/symcc_runtime
|
cd libafl_concolic/symcc_runtime
|
||||||
cargo publish "$@"
|
cargo publish "$@"
|
||||||
cd ../.. || exit 1
|
cd ../.. || exit 1
|
||||||
|
|
||||||
|
cd libafl_libfuzzer
|
||||||
|
cargo publish "$@"
|
||||||
|
cd ../.. || exit 1
|
||||||
|
Loading…
x
Reference in New Issue
Block a user