Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prep for publishing libafl_libfuzzer #1457

Merged
merged 6 commits into from
Aug 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .github/workflows/build_and_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,6 @@ jobs:
with:
profile: minimal
toolchain: stable
components: llvm-tools
- name: Install and cache deps
uses: awalsh128/[email protected]
with:
Expand Down
1 change: 0 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,3 @@ lto = true
codegen-units = 1
opt-level = 3
debug = true

6 changes: 6 additions & 0 deletions fuzzers/fuzzbench/fuzz.c
Original file line number Diff line number Diff line change
@@ -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;
}

Expand Down
15 changes: 14 additions & 1 deletion libafl_libfuzzer/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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",
domenukk marked this conversation as resolved.
Show resolved Hide resolved
]
49 changes: 4 additions & 45 deletions libafl_libfuzzer/build.rs
Original file line number Diff line number Diff line change
@@ -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!(
Expand Down Expand Up @@ -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
domenukk marked this conversation as resolved.
Show resolved Hide resolved

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++");
}
6 changes: 6 additions & 0 deletions libafl_libfuzzer/libafl_libfuzzer_runtime/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
34 changes: 17 additions & 17 deletions libafl_libfuzzer/libafl_libfuzzer_runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this not checked in CI?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure, I thought it was but apparently somehow missed.

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,
Expand Down
70 changes: 69 additions & 1 deletion libafl_libfuzzer/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,86 @@
//! `libafl_libfuzzer` offers a "permanent" replacement for the now-deprecated libfuzzer
//!
//! ## Usage
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Want to copy&paste this into the book as well? might make sense (or include it from there)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or maybe it's too technical

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not too technical. Makes sense to include it since many folks might be coming from libfuzzer.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What section should it be put under? Its own? It can be used with both C/C++ and Rust targets but needs different setups.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure sounds like an extra section to me

//!
//! 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.
//!
//! This crate links to a (separately built) internal crate which affords the actual functionality.
//! 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,
Expand Down
18 changes: 18 additions & 0 deletions libafl_targets/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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")]
Expand Down
2 changes: 1 addition & 1 deletion libafl_targets/src/cmplog.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
4 changes: 4 additions & 0 deletions scripts/publish.sh
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,7 @@ fi
cd libafl_concolic/symcc_runtime
cargo publish "$@"
cd ../.. || exit 1

cd libafl_libfuzzer
domenukk marked this conversation as resolved.
Show resolved Hide resolved
cargo publish "$@"
cd ../.. || exit 1