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

Introduce LLVMFuzzerInitialize support #128

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,20 @@ Released YYYY-MM-DD.

--------------------------------------------------------------------------------

## 0.4.9

Released YYYY-MM-DD.

### Added

* The `example_init` demonstrates how to pass an initialization code block to the `fuzz_target!` macro.

### Changed

* The `fuzz_target!` macro now supports the generation of `LLVMFuzzerInitialize` to execute initialization code once before running the fuzzer. This change is not breaking and is completely backward compatible.

--------------------------------------------------------------------------------

## 0.4.8

Released 2024-11-07.
Expand Down
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ members = [
"./example/fuzz",
"./example_arbitrary/fuzz",
"./example_crossover/fuzz",
"./example_init/fuzz",
"./example_mutator/fuzz",
]

Expand Down
6 changes: 6 additions & 0 deletions ci/script.sh
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,10 @@ cargo fuzz build --dev
(! cargo fuzz run --release boom -- -runs=10000000)
popd

pushd ./example_init
cargo fuzz build
cargo fuzz build --dev
(! cargo fuzz run --release bigbang -- -runs=10000000)
popd

echo "All good!"
1 change: 1 addition & 0 deletions example_init/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
crash-*
6 changes: 6 additions & 0 deletions example_init/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[package]
name = "example_init"
version = "0.1.0"
edition = "2021"

[dependencies]
16 changes: 16 additions & 0 deletions example_init/fuzz/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[package]
name = "example_init-fuzz"
version = "0.1.0"
authors = ["Andrea Cappa"]
edition = "2018"

[package.metadata]
cargo-fuzz = true

[dependencies]
libfuzzer-sys = { path = "../.." }
example_init = { path = ".." }

[[bin]]
name = "bigbang"
path = "fuzz_targets/bigbang.rs"
16 changes: 16 additions & 0 deletions example_init/fuzz/fuzz_targets/bigbang.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#![no_main]

use libfuzzer_sys::fuzz_target;

fuzz_target!(
init: {
// Custom initialization code here
println!("Initializing fuzzer...");
std::env::set_var("MY_FUZZER_INIT", "1337");
},
|data: &[u8]| {
if std::env::var("MY_FUZZER_INIT").unwrap() == "1337" && data == "bigbang!".as_bytes() {
panic!("success!");
}
example_init::bigbang(data);
});
5 changes: 5 additions & 0 deletions example_init/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
pub fn bigbang(data: &[u8]) {
if data == &b"bigbang!"[..] {
panic!("bigbang!");
}
}
86 changes: 63 additions & 23 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,24 +78,11 @@ pub fn rust_libfuzzer_debug_path() -> &'static Option<String> {
RUST_LIBFUZZER_DEBUG_PATH.get_or_init(|| std::env::var("RUST_LIBFUZZER_DEBUG_PATH").ok())
}

#[doc(hidden)]
/* #[doc(hidden)]
#[export_name = "LLVMFuzzerInitialize"]
pub fn initialize(_argc: *const isize, _argv: *const *const *const u8) -> isize {
// Registers a panic hook that aborts the process before unwinding.
// It is useful to abort before unwinding so that the fuzzer will then be
// able to analyse the process stack frames to tell different bugs appart.
//
// HACK / FIXME: it would be better to use `-C panic=abort` but it's currently
// impossible to build code using compiler plugins with this flag.
// We will be able to remove this code when
// https://github.com/rust-lang/cargo/issues/5423 is fixed.
let default_hook = ::std::panic::take_hook();
::std::panic::set_hook(Box::new(move |panic_info| {
default_hook(panic_info);
::std::process::abort();
}));
0
}
} */

/// Define a fuzz target.
///
Expand Down Expand Up @@ -198,9 +185,31 @@ pub fn initialize(_argc: *const isize, _argv: *const *const *const u8) -> isize
/// `"arbitrary-derive"` cargo feature.
#[macro_export]
macro_rules! fuzz_target {
(|$bytes:ident| $body:expr) => {
(init: $init:expr, |$bytes:ident| $body:expr) => {
const _: () = {
/// Auto-generated function
/// Auto-generated functions
/// LLVMFuzzerInitialize is called once before the fuzzer starts.
#[no_mangle]
pub extern "C" fn LLVMFuzzerInitialize(_argc: *const isize, _argv: *const *const *const u8) -> isize {
// Registers a panic hook that aborts the process before unwinding.
// It is useful to abort before unwinding so that the fuzzer will then be
// able to analyse the process stack frames to tell different bugs appart.
//
// HACK / FIXME: it would be better to use `-C panic=abort` but it's currently
// impossible to build code using compiler plugins with this flag.
// We will be able to remove this code when
// https://github.com/rust-lang/cargo/issues/5423 is fixed.
let default_hook = std::panic::take_hook();
std::panic::set_hook(Box::new(move |panic_info| {
default_hook(panic_info);
std::process::abort();
}));

// Supplied init code
$init;
0
}

#[no_mangle]
pub extern "C" fn rust_fuzzer_test_input(bytes: &[u8]) -> i32 {
// When `RUST_LIBFUZZER_DEBUG_PATH` is set, write the debug
Expand Down Expand Up @@ -241,16 +250,50 @@ macro_rules! fuzz_target {
};

(|$data:ident: &[u8]| $body:expr) => {
$crate::fuzz_target!(|$data| $body);
$crate::fuzz_target!(init: (), |$data| $body);
};

(|$data:ident: $dty:ty| $body:expr) => {
$crate::fuzz_target!(|$data: $dty| -> () { $body });
$crate::fuzz_target!(init: (), |$data: $dty| -> () { $body });
};

(|$data:ident: $dty:ty| -> $rty:ty $body:block) => {
$crate::fuzz_target!(init: (), |$data: $dty| -> $rty { $body });
};

(init: $init:expr, |$data:ident: &[u8]| $body:expr) => {
$crate::fuzz_target!(init: $init, |$data| $body);
};

(init: $init:expr, |$data:ident: $dty:ty| $body:expr) => {
$crate::fuzz_target!(init: $init, |$data: $dty| -> () { $body });
};

(init: $init:expr, |$data:ident: $dty:ty| -> $rty:ty $body:block) => {
const _: () = {
/// Auto-generated function
/// Auto-generated functions
/// LLVMFuzzerInitialize is called once before the fuzzer starts.
#[no_mangle]
pub extern "C" fn LLVMFuzzerInitialize(_argc: *const isize, _argv: *const *const *const u8) -> isize {
// Registers a panic hook that aborts the process before unwinding.
// It is useful to abort before unwinding so that the fuzzer will then be
// able to analyse the process stack frames to tell different bugs appart.
//
// HACK / FIXME: it would be better to use `-C panic=abort` but it's currently
// impossible to build code using compiler plugins with this flag.
// We will be able to remove this code when
// https://github.com/rust-lang/cargo/issues/5423 is fixed.
let default_hook = std::panic::take_hook();
std::panic::set_hook(Box::new(move |panic_info| {
default_hook(panic_info);
std::process::abort();
}));

// Supplied init code
$init;
0
}

#[no_mangle]
pub extern "C" fn rust_fuzzer_test_input(bytes: &[u8]) -> i32 {
use $crate::arbitrary::{Arbitrary, Unstructured};
Expand All @@ -271,8 +314,6 @@ macro_rules! fuzz_target {
// When `RUST_LIBFUZZER_DEBUG_PATH` is set, write the debug
// formatting of the input to that file. This is only intended for
// `cargo fuzz`'s use!

// `RUST_LIBFUZZER_DEBUG_PATH` is set in initialization.
if let Some(path) = $crate::rust_libfuzzer_debug_path() {
use std::io::Write;
let mut file = std::fs::File::create(path)
Expand All @@ -294,7 +335,6 @@ macro_rules! fuzz_target {
result.to_libfuzzer_code()
}

// See above for why this is split to a separate function.
#[inline(never)]
fn __libfuzzer_sys_run($data: $dty) -> $rty {
$body
Expand Down