Template out libafl_libfuzzer (#2398)

* template out libafl_libfuzzer

* fix some final path oddities

* missed a spot
This commit is contained in:
Addison Crump 2024-07-15 19:10:51 +02:00 committed by GitHub
parent fed61eb6b8
commit 50a4a0abd9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
29 changed files with 201 additions and 137 deletions

View File

@ -36,6 +36,7 @@ exclude = [
"libafl_concolic/symcc_libafl", "libafl_concolic/symcc_libafl",
"libafl_frida", "libafl_frida",
"libafl_libfuzzer", "libafl_libfuzzer",
"libafl_libfuzzer_runtime",
"libafl_nyx", "libafl_nyx",
"libafl_qemu", "libafl_qemu",
"libafl_tinyinst", "libafl_tinyinst",

View File

@ -131,8 +131,9 @@ COPY libafl_concolic/symcc_runtime libafl_concolic/symcc_runtime
COPY libafl_concolic/test libafl_concolic/test COPY libafl_concolic/test libafl_concolic/test
COPY libafl_nyx/src libafl_nyx/src COPY libafl_nyx/src libafl_nyx/src
RUN touch libafl_nyx/src/lib.rs RUN touch libafl_nyx/src/lib.rs
COPY libafl_libfuzzer_runtime libafl_libfuzzer_runtime
COPY libafl_libfuzzer/src libafl_libfuzzer/src COPY libafl_libfuzzer/src libafl_libfuzzer/src
COPY libafl_libfuzzer/libafl_libfuzzer_runtime libafl_libfuzzer/libafl_libfuzzer_runtime COPY libafl_libfuzzer/runtime libafl_libfuzzer/runtime
COPY libafl_libfuzzer/build.rs libafl_libfuzzer/build.rs COPY libafl_libfuzzer/build.rs libafl_libfuzzer/build.rs
RUN touch libafl_libfuzzer/src/lib.rs RUN touch libafl_libfuzzer/src/lib.rs
RUN cargo build && cargo build --release RUN cargo build && cargo build --release

View File

@ -13,8 +13,7 @@ include = [
"/src", "/src",
"/Cargo.toml", "/Cargo.toml",
"/build.rs", "/build.rs",
"/libafl_libfuzzer_runtime", "/runtime",
"!/libafl_libfuzzer_runtime/target",
] ]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
@ -22,6 +21,7 @@ include = [
[build-dependencies] [build-dependencies]
cc = "1.0" cc = "1.0"
rustversion = "1.0" rustversion = "1.0"
toml = { version = "0.8.14", features = ["preserve_order"] }
[features] [features]
default = ["fork"] default = ["fork"]
@ -43,6 +43,9 @@ embed-runtime = []
## 🐇 ## 🐇
rabbit = [] rabbit = []
## For testing and publishing purposes only: enforce that the runtime uses versions rather than paths
libafl-libfuzzer-use-version = []
[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", optional = true } document-features = { version = "0.2", optional = true }

View File

@ -83,13 +83,13 @@ CXXFLAGS='-fsanitize=fuzzer-no-link'
The runtime for `libafl_libfuzzer` may be used standalone as a direct replacement for libFuzzer with other targets as The runtime for `libafl_libfuzzer` may be used standalone as a direct replacement for libFuzzer with other targets as
well. well.
To do so, [ensure a recent nightly version of Rust is installed](https://rustup.rs/), then enter the To do so, [ensure a recent nightly version of Rust is installed](https://rustup.rs/), then enter the
[`libafl_libfuzzer_runtime`](libafl_libfuzzer_runtime) folder and build the runtime with the following command: [`libafl_libfuzzer_runtime`](../libafl_libfuzzer_runtime) folder and build the runtime with the following command:
```bash ```bash
./build.sh ./build.sh
``` ```
The static library will be available at `libFuzzer.a` in the [`libafl_libfuzzer_runtime`](libafl_libfuzzer_runtime) The static library will be available at `libFuzzer.a` in the [`libafl_libfuzzer_runtime`](../libafl_libfuzzer_runtime)
directory. directory.
If you encounter build failures without clear error outputs that help you resolve the issue, please [submit an issue]. If you encounter build failures without clear error outputs that help you resolve the issue, please [submit an issue].
@ -144,7 +144,8 @@ to partial support of libfuzzer flags, `libafl_libfuzzer` offers:
- `-fork` and `-jobs` - `-fork` and `-jobs`
- in `libafl_libfuzzer`, these are synonymous - in `libafl_libfuzzer`, these are synonymous
- `-ignore_crashes`, `-ignore_ooms`, and `-ignore_timeouts` - `-ignore_crashes`, `-ignore_ooms`, and `-ignore_timeouts`
- note that setting `-tui=1` enables these flags by default, so you'll need to explicitly mention `-ignore_...=0` to disable them - note that setting `-tui=1` enables these flags by default, so you'll need to explicitly mention `-ignore_...=0` to
disable them
- `-rss_limit_mb` and `-malloc_limit_mb` - `-rss_limit_mb` and `-malloc_limit_mb`
- `-ignore_remaining_args` - `-ignore_remaining_args`
- `-shrink` - `-shrink`
@ -152,7 +153,11 @@ to partial support of libfuzzer flags, `libafl_libfuzzer` offers:
- `-close_fd_mask` - `-close_fd_mask`
[libFuzzer]: https://llvm.org/docs/LibFuzzer.html [libFuzzer]: https://llvm.org/docs/LibFuzzer.html
[`libfuzzer-sys`]: https://docs.rs/libfuzzer-sys/ [`libfuzzer-sys`]: https://docs.rs/libfuzzer-sys/
[de-facto deprecation of libFuzzer]: https://llvm.org/docs/LibFuzzer.html#status [de-facto deprecation of libFuzzer]: https://llvm.org/docs/LibFuzzer.html#status
[submit an issue]: https://github.com/AFLplusplus/LibAFL/issues/new/choose [submit an issue]: https://github.com/AFLplusplus/LibAFL/issues/new/choose
[grimoire]: https://www.usenix.org/conference/usenixsecurity19/presentation/blazytko [grimoire]: https://www.usenix.org/conference/usenixsecurity19/presentation/blazytko

View File

@ -1,4 +1,6 @@
use std::{ use std::{
error::Error,
fs,
fs::File, fs::File,
io::{BufRead, BufReader, BufWriter, Write}, io::{BufRead, BufReader, BufWriter, Write},
path::{Path, PathBuf}, path::{Path, PathBuf},
@ -12,25 +14,25 @@ const NAMESPACE: &str = "__libafl";
const NAMESPACE_LEN: usize = NAMESPACE.as_bytes().len(); const NAMESPACE_LEN: usize = NAMESPACE.as_bytes().len();
#[allow(clippy::too_many_lines)] #[allow(clippy::too_many_lines)]
fn main() { fn main() -> Result<(), Box<dyn Error>> {
if cfg!(any(clippy, docsrs)) { if cfg!(any(clippy, docsrs)) {
return; // skip when clippy or docs is running return Ok(()); // skip when clippy or docs is running
} }
if cfg!(not(any(target_os = "linux", target_os = "macos"))) { if cfg!(not(any(target_os = "linux", target_os = "macos"))) {
println!( println!(
"cargo:warning=The libafl_libfuzzer runtime may only be built for linux or macos; failing fast." "cargo:warning=The libafl_libfuzzer runtime may only be built for linux or macos; failing fast."
); );
return; return Ok(());
} }
println!("cargo:rerun-if-changed=libafl_libfuzzer_runtime/src"); println!("cargo:rerun-if-changed=libafl_libfuzzer_runtime/src");
println!("cargo:rerun-if-changed=libafl_libfuzzer_runtime/Cargo.toml");
println!("cargo:rerun-if-changed=libafl_libfuzzer_runtime/build.rs"); println!("cargo:rerun-if-changed=libafl_libfuzzer_runtime/build.rs");
let custom_lib_dir = let custom_lib_dir =
AsRef::<Path>::as_ref(&std::env::var_os("OUT_DIR").unwrap()).join("libafl_libfuzzer"); AsRef::<Path>::as_ref(&std::env::var_os("OUT_DIR").unwrap()).join("libafl_libfuzzer");
std::fs::create_dir_all(&custom_lib_dir) let custom_lib_target = custom_lib_dir.join("target");
fs::create_dir_all(&custom_lib_target)
.expect("Couldn't create the output directory for the fuzzer runtime build"); .expect("Couldn't create the output directory for the fuzzer runtime build");
let lib_src: PathBuf = AsRef::<Path>::as_ref(&std::env::var_os("CARGO_MANIFEST_DIR").unwrap()) let lib_src: PathBuf = AsRef::<Path>::as_ref(&std::env::var_os("CARGO_MANIFEST_DIR").unwrap())
@ -51,8 +53,6 @@ fn main() {
.env("PATH", std::env::var_os("PATH").unwrap()) .env("PATH", std::env::var_os("PATH").unwrap())
.current_dir(&lib_src); .current_dir(&lib_src);
let _ = std::fs::rename(lib_src.join("Cargo.toml.orig"), lib_src.join("Cargo.toml"));
command.arg("build"); command.arg("build");
let mut features = vec![]; let mut features = vec![];
@ -69,19 +69,79 @@ fn main() {
.arg("--release") .arg("--release")
.arg("--no-default-features") .arg("--no-default-features")
.arg("--target-dir") .arg("--target-dir")
.arg(&custom_lib_dir) .arg(&custom_lib_target)
.arg("--target") .arg("--target")
.arg(std::env::var_os("TARGET").unwrap()); .arg(std::env::var_os("TARGET").unwrap());
// detect if we are a version or path/git dep, or testing version-based behavior
if fs::exists("../libafl_libfuzzer_runtime")? && !cfg!(feature = "libafl-libfuzzer-use-version")
{
command.current_dir("../libafl_libfuzzer_runtime");
} else {
// we are being used as a version dep; we need to create the package virtually
// remove old files; we need to trigger a rebuild if our path changes!
let _ = fs::remove_file(custom_lib_dir.join("src"));
let _ = fs::remove_dir_all(custom_lib_dir.join("src")); // maybe a dir in windows
let _ = fs::remove_file(custom_lib_dir.join("build.rs"));
let _ = fs::remove_file(custom_lib_dir.join("Cargo.toml"));
#[cfg(unix)]
{
// create symlinks for all the source files
use std::os::unix::fs::symlink;
// canonicalize can theoretically fail if we are within a non-executable directory?
symlink(fs::canonicalize("runtime/src")?, custom_lib_dir.join("src"))?;
symlink(
fs::canonicalize("runtime/build.rs")?,
custom_lib_dir.join("build.rs"),
)?;
}
#[cfg(not(unix))]
{
todo!("copy all the source files"); // we don't support libafl_libfuzzer for others rn
}
let mut template: toml::Value =
toml::from_str(&fs::read_to_string("runtime/Cargo.toml.template")?)?;
let toml::Value::Table(root) = &mut template else {
unreachable!("Invalid Cargo.toml");
};
root.insert(
"workspace".to_string(),
toml::Value::Table(toml::Table::new()),
);
let Some(toml::Value::Table(deps)) = root.get_mut("dependencies") else {
unreachable!("Invalid Cargo.toml");
};
let version = env!("CARGO_PKG_VERSION");
for (_name, spec) in deps {
if let toml::Value::Table(spec) = spec {
// replace all path deps with version deps
if spec.remove("path").is_some() {
spec.insert(
"version".to_string(),
toml::Value::String(version.to_string()),
);
}
}
}
let serialized = toml::to_string(&template)?;
fs::write(custom_lib_dir.join("Cargo.toml"), serialized)?;
// build in this filled out template
command.current_dir(custom_lib_dir);
}
assert!( assert!(
command.status().map_or(false, |s| s.success()), command.status().map_or(false, |s| s.success()),
"Couldn't build runtime crate! Did you remember to use nightly? (`rustup default nightly` to install)" "Couldn't build runtime crate! Did you remember to use nightly? (`rustup default nightly` to install)"
); );
let mut archive_path = custom_lib_dir.join(std::env::var_os("TARGET").unwrap()); let mut archive_path = custom_lib_target.join(std::env::var_os("TARGET").unwrap());
archive_path.push("release"); archive_path.push("release");
if cfg!(unix) {
archive_path.push("libafl_libfuzzer_runtime.a"); archive_path.push("libafl_libfuzzer_runtime.a");
let target_libdir = Command::new("rustc") let target_libdir = Command::new("rustc")
.args(["--print", "target-libdir"]) .args(["--print", "target-libdir"])
@ -94,8 +154,8 @@ fn main() {
let rust_objcopy = target_libdir.join("../bin/llvm-objcopy"); let rust_objcopy = target_libdir.join("../bin/llvm-objcopy");
let nm = target_libdir.join("../bin/llvm-nm"); let nm = target_libdir.join("../bin/llvm-nm");
let redefined_archive_path = custom_lib_dir.join("libFuzzer.a"); let redefined_archive_path = custom_lib_target.join("libFuzzer.a");
let redefined_symbols = custom_lib_dir.join("redefs.txt"); let redefined_symbols = custom_lib_target.join("redefs.txt");
let mut nm_child = Command::new(nm) let mut nm_child = Command::new(nm)
.arg(&archive_path) .arg(&archive_path)
@ -198,7 +258,7 @@ fn main() {
println!( println!(
"cargo:rustc-link-search=native={}", "cargo:rustc-link-search=native={}",
custom_lib_dir.to_str().unwrap() custom_lib_target.to_str().unwrap()
); );
println!("cargo:rustc-link-lib=static=Fuzzer"); println!("cargo:rustc-link-lib=static=Fuzzer");
@ -207,5 +267,5 @@ fn main() {
} else { } else {
println!("cargo:rustc-link-lib=stdc++"); println!("cargo:rustc-link-lib=stdc++");
} }
} Ok(())
} }

View File

@ -1,2 +0,0 @@
group_imports = "StdExternalCrate"
imports_granularity = "Crate"

View File

@ -1,7 +0,0 @@
#!/bin/bash
set -x
mv libafl_libfuzzer_runtime/Cargo.toml libafl_libfuzzer_runtime/Cargo.toml.orig
cargo publish --allow-dirty --no-verify "$@"
mv libafl_libfuzzer_runtime/Cargo.toml.orig libafl_libfuzzer_runtime/Cargo.toml

View File

@ -24,16 +24,14 @@ inherits = "release"
debug = false debug = false
strip = true strip = true
[lib] [lib]
name = "afl_libfuzzer_runtime" # TODO fix name once cargo-fuzz stops stripping double-prefixes name = "afl_libfuzzer_runtime" # historically, cargo-fuzz strips double-prefixes; maintain compat
path = "src/lib.rs"
crate-type = ["staticlib", "rlib"] crate-type = ["staticlib", "rlib"]
[dependencies] [dependencies]
libafl = { path = "../../libafl", default-features = false, features = ["std", "derive", "llmp_compression", "rand_trait", "regex", "errors_backtrace", "serdeany_autoreg", "tui_monitor", "unicode"] } libafl = { path = "../libafl", default-features = false, features = ["std", "derive", "llmp_compression", "rand_trait", "regex", "errors_backtrace", "serdeany_autoreg", "tui_monitor", "unicode"] }
libafl_bolts = { path = "../../libafl_bolts", default-features = false, features = ["std", "derive", "llmp_compression", "rand_trait", "serdeany_autoreg", "errors_backtrace"] } libafl_bolts = { path = "../libafl_bolts", default-features = false, features = ["std", "derive", "llmp_compression", "rand_trait", "serdeany_autoreg", "errors_backtrace"] }
libafl_targets = { path = "../../libafl_targets", features = ["sancov_8bit", "sancov_cmplog", "sancov_value_profile", "sancov_pcguard", "libfuzzer", "libfuzzer_oom", "libfuzzer_define_run_driver", "libfuzzer_interceptors", "sanitizers_flags", "whole_archive", "sanitizer_interfaces"] } libafl_targets = { path = "../libafl_targets", features = ["sancov_8bit", "sancov_cmplog", "sancov_value_profile", "sancov_pcguard", "libfuzzer", "libfuzzer_oom", "libfuzzer_define_run_driver", "libfuzzer_interceptors", "sanitizers_flags", "whole_archive", "sanitizer_interfaces"] }
ahash = { version = "0.8.3", default-features = false } ahash = { version = "0.8.3", default-features = false }
libc = "0.2.1" libc = "0.2.1"
@ -46,12 +44,8 @@ hashbrown = "0.14"
# for identifying if we can grimoire-ify # for identifying if we can grimoire-ify
utf8-chars = "3.0.1" utf8-chars = "3.0.1"
env_logger = "0.10" env_logger = "0.10"
[build-dependencies] [build-dependencies]
bindgen = "0.69.4" bindgen = "0.69.4"
cc = { version = "1.0", features = ["parallel"] } cc = { version = "1.0", features = ["parallel"] }
[workspace]

View File

@ -0,0 +1 @@
../libafl_libfuzzer/runtime/Cargo.toml.template

View File

@ -0,0 +1,6 @@
# libafl_libfuzzer_runtime
This is the runtime for `libafl_libfuzzer`.
Please see the [`libafl_libfuzzer`](../libafl_libfuzzer) documentation for details.
This crate should not be used alone except in very special circumstances.

View File

@ -0,0 +1 @@
../libafl_libfuzzer/runtime/build.rs

View File

@ -0,0 +1 @@
../libafl_libfuzzer/runtime/src

View File

@ -20,7 +20,7 @@ RUST_BACKTRACE=full cargo +nightly clippy --all --all-features --no-deps --tests
-A clippy::unreadable-literal -A clippy::unreadable-literal
if [[ "$OSTYPE" == "linux-gnu"* ]]; then if [[ "$OSTYPE" == "linux-gnu"* ]]; then
cd libafl_libfuzzer/libafl_libfuzzer_runtime cd libafl_libfuzzer_runtime
RUST_BACKTRACE=full cargo +nightly clippy --all --all-features --no-deps --tests --examples --benches -- -Z macro-backtrace \ RUST_BACKTRACE=full cargo +nightly clippy --all --all-features --no-deps --tests --examples --benches -- -Z macro-backtrace \
-D clippy::all \ -D clippy::all \
-D clippy::pedantic \ -D clippy::pedantic \

View File

@ -78,5 +78,5 @@ cargo publish "$@" --allow-dirty
cd ../.. || exit 1 cd ../.. || exit 1
cd libafl_libfuzzer cd libafl_libfuzzer
./publish.sh "$@" cargo publish "$@"
cd .. || exit 1 cd .. || exit 1