Skip to content

Commit

Permalink
Enhance fuzzing capabilities with LLVMFuzzerInitialize support
Browse files Browse the repository at this point in the history
- Added `example_init` to demonstrate the use of initialization code with the `fuzz_target!` macro.
- Updated `fuzz_target!` macro to support an `init` parameter for executing initialization code before fuzzing.
- Updated CI script to build and run the new example.
  • Loading branch information
zi0Black committed Dec 21, 2024
1 parent a247317 commit d561921
Show file tree
Hide file tree
Showing 9 changed files with 128 additions and 23 deletions.
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

0 comments on commit d561921

Please sign in to comment.