8000 Merge pull request #128 from zi0Black/support-for-LLVMFuzzerInitialize · rust-fuzz/libfuzzer@bc6ea8b · GitHub
[go: up one dir, main page]

Skip to content

Commit bc6ea8b

Browse files
authored
Merge pull request #128 from zi0Black/support-for-LLVMFuzzerInitialize
Introduce LLVMFuzzerInitialize support
2 parents a247317 + 55cb6cd commit bc6ea8b

File tree

9 files changed

+154
-10
lines changed

9 files changed

+154
-10
lines changed

CHANGELOG.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,20 @@ Released YYYY-MM-DD.
2828

2929
--------------------------------------------------------------------------------
3030

31+
## 0.4.9
32+
33+
Released YYYY-MM-DD.
34+
35+
### Added
36+
37+
* The `example_init` demonstrates how to pass an initialization code block to the `fuzz_target!` macro.
38+
39+
### Changed
40+
41+
* 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.
42+
43+
--------------------------------------------------------------------------------
44+
3145
## 0.4.8
3246

3347
Released 2024-11-07.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ members = [
2424
"./example/fuzz",
2525
"./example_arbitrary/fuzz",
2626
"./example_crossover/fuzz",
27+
"./example_init/fuzz",
2728
"./example_mutator/fuzz",
2829
]
2930

ci/script.sh

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,10 @@ cargo fuzz build --dev
3636
(! cargo fuzz run --release boom -- -runs=10000000)
3737
popd
3838

39+
pushd ./example_init
40+
cargo fuzz build
41+
cargo fuzz build --dev
42+
(! cargo fuzz run --release bigbang -- -runs=10000000)
43+
popd
44+
3945
echo "All good!"

example_init/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
crash-*

example_init/Cargo.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
[package]
2+
name = "example_init"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
[dependencies]

example_init/fuzz/Cargo.toml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
[package]
2+
name = "example_init-fuzz"
3+
version = "0.1.0"
4+
authors = ["Andrea Cappa"]
5+
edition = "2018"
6+
7+
[package.metadata]
8+
cargo-fuzz = true
9+
10+
[dependencies]
11+
libfuzzer-sys = { path = "../.." }
12+
example_init = { path = ".." }
13+
14+
[[bin]]
15+
name = "bigbang"
16+
path = "fuzz_targets/bigbang.rs"
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#![no_main]
2+
3+
use libfuzzer_sys::fuzz_target;
4+
5+
fuzz_target!(
6+
init: {
7+
// Custom initialization code here
8+
println!("Initializing fuzzer...");
9+
example_init::initialize();
10+
},
11+
|data: &[u8]| {
12+
example_init::bigbang(data);
13+
});

example_init/src/lib.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
use std::sync::OnceLock;
2+
3+
static EXTRA_DATA: OnceLock<&'static str> = OnceLock::new();
4+
5+
pub fn bigbang(data: &[u8]) {
6+
// The fuzzer needs to mutate input to be "bigbang!"
7+
// Init needs to be called before bigbang() is called
8+
// This actually proves that the fuzzer is calling init before bigbang
9+
if data == &b"bigbang!"[..] && is_initialized() {
10+
panic!("bigbang!");
11+
}
12+
}
13+
14+
pub fn initialize() {
15+
EXTRA_DATA
16+
.set("initialized")
17+
.expect("should only initialize once");
18+
}
19+
20+
pub fn is_initialized() -> bool {
21+
EXTRA_DATA.get().is_some()
22+
}

src/lib.rs

Lines changed: 75 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,6 @@ pub fn rust_libfuzzer_debug_path() -> &'static Option<String> {
7979
}
8080

8181
#[doc(hidden)]
82-
#[export_name = "LLVMFuzzerInitialize"]
8382
pub fn initialize(_argc: *const isize, _argv: *const *const *const u8) -> isize {
8483
// Registers a panic hook that aborts the process before unwinding.
8584
// It is useful to abort before unwinding so that the fuzzer will then be
@@ -89,10 +88,10 @@ pub fn initialize(_argc: *const isize, _argv: *const *const *const u8) -> isize
8988
// impossible to build code using compiler plugins with this flag.
9089
// We will be able to remove this code when
9190
// https://github.com/rust-lang/cargo/issues/5423 is fixed.
92-
let default_hook = ::std::panic::take_hook();
93-
::std::panic::set_hook(Box::new(move |panic_info| {
91+
let default_hook = std::panic::take_hook();
92+
std::panic::set_hook(Box::new(move |panic_info| {
9493
default_hook(panic_info);
95-
::std::process::abort();
94+
std::process::abort();
9695
}));
9796
0
9897
}
@@ -196,11 +195,48 @@ pub fn initialize(_argc: *const isize, _argv: *const *const *const u8) -> isize
196195
///
197196
/// You can also enable the `arbitrary` crate's custom derive via this crate's
198197
/// `"arbitrary-derive"` cargo feature.
198+
///
199+
/// ## Init Code
200+
///
201+
/// Init code to the fuzz target by using the `init` keyword. This is called once before the fuzzer starts.
202+
/// Supports short |input| or |input: <type>| syntax.
203+
///
204+
/// ```no_run
205+
/// #![no_main]
206+
///
207+
/// use libfuzzer_sys::fuzz_target;
208+
/// use std::collections::HashSet;
209+
/// use std::sync::OnceLock;
210+
///
211+
/// static DICTIONARY: OnceLock<HashSet<String>> = OnceLock::new();
212+
///
213+
/// fuzz_target!(
214+
/// init: {
215+
/// let read_dictionary = |_| unimplemented!();
216+
/// let dictionary = read_dictionary("/usr/share/dict/words");
217+
/// DICTIONARY.set(dictionary).unwrap();
218+
/// },
219+
/// |input| {
220+
/// // Use the initialized `DICTIONARY` here...
221+
/// }
222+
/// );
223+
/// ```
224+
///
199225
#[macro_export]
200226
macro_rules! fuzz_target {
201-
(|$bytes:ident| $body:expr) => {
227+
(init: $init:expr, |$bytes:ident| $body:expr) => {
202228
const _: () = {
203-
/// Auto-generated function
229+
/// Auto-generated functions
230+
/// LLVMFuzzerInitialize is called once before the fuzzer starts.
231+
#[no_mangle]
232+
pub extern "C" fn LLVMFuzzerInitialize(_argc: *const isize, _argv: *const *const *const u8) -> isize {
233+
$crate::initialize(_argc, _argv);
234+
235+
// Supplied init code
236+
$init;
237+
0
238+
}
239+
204240
#[no_mangle]
205241
pub extern "C" fn rust_fuzzer_test_input(bytes: &[u8]) -> i32 {
206242
// When `RUST_LIBFUZZER_DEBUG_PATH` is set, write the debug
@@ -240,17 +276,47 @@ macro_rules! fuzz_target {
240276
};
241277
};
242278

279+
(|$bytes:ident| $body:expr) => {
280+
$crate::fuzz_target!(|$bytes: &[u8]| $body);
281+
};
282+
243283
(|$data:ident: &[u8]| $body:expr) => {
244-
$crate::fuzz_target!(|$data| $body);
284+
$crate::fuzz_target!(init: (), |$data| $body);
245285
};
246286

247287
(|$data:ident: $dty:ty| $body:expr) => {
248-
$crate::fuzz_target!(|$data: $dty| -> () { $body });
288+
$crate::fuzz_target!(init: (), |$data: $dty| -> () { $body });
249289
};
250290

251291
(|$data:ident: $dty:ty| -> $rty:ty $body:block) => {
292+
$crate::fuzz_target!(init: (), |$data: $dty| -> $rty { $body });
293+
};
294+
295+
(init: $init:expr, |$data:ident: &[u8]| $body:expr) => {
296+
$crate::fuzz_target!(init: $init, |$data| $body);
297+
};
298+
299+
(init: $init:expr, |$bytes:ident| $body:expr) => {
300+
$crate::fuzz_target!(init: $init, |$bytes: &[u8]| $body);
301+
};
302+
303+
(init: $init:expr, |$data:ident: $dty:ty| $body:expr) => {
304+
$crate::fuzz_target!(init: $init, |$data: $dty| -> () { $body });
305+
};
306+
307+
(init: $init:expr, |$data:ident: $dty:ty| -> $rty:ty $body:block) => {
252308
const _: () = {
253-
/// Auto-generated function
309+
/// Auto-generated functions
310+
/// LLVMFuzzerInitialize is called once before the fuzzer starts.
311+
#[no_mangle]
312+
pub extern "C" fn LLVMFuzzerInitialize(_argc: *const isize, _argv: *const *const *const u8) -> isize {
313+
$crate::initialize(_argc, _argv);
314+
315+
// Supplied init code
316+
$init;
317+
0
318+
}
319+
254320
#[no_mangle]
255321
pub extern "C" fn rust_fuzzer_test_input(bytes: &[u8]) -> i32 {
256322
use $crate::arbitrary::{Arbitrary, Unstructured};
@@ -293,7 +359,6 @@ macro_rules! fuzz_target {
293359
let result = ::libfuzzer_sys::Corpus::from(__libfuzzer_sys_run(data));
294360
result.to_libfuzzer_code()
295361
}
296-
297362
// See above for why this is split to a separate function.
298363
#[inline(never)]
299364
fn __libfuzzer_sys_run($data: $dty) -> $rty {

0 commit comments

Comments
 (0)
0