Coverage Report

Created: 2025-03-06 06:38

/rust/registry/src/index.crates.io-6f17d22bba15001f/libfuzzer-sys-0.4.2/src/lib.rs
Line
Count
Source (jump to first uncovered line)
1
//! Bindings to [libFuzzer](http://llvm.org/docs/LibFuzzer.html): a runtime for
2
//! coverage-guided fuzzing.
3
//!
4
//! See [the `cargo-fuzz`
5
//! guide](https://rust-fuzz.github.io/book/cargo-fuzz.html) for a usage
6
//! tutorial.
7
//!
8
//! The main export of this crate is [the `fuzz_target!`
9
//! macro](./macro.fuzz_target.html), which allows you to define targets for
10
//! libFuzzer to exercise.
11
12
#![deny(missing_docs, missing_debug_implementations)]
13
14
pub use arbitrary;
15
use once_cell::sync::OnceCell;
16
17
extern "C" {
18
    // We do not actually cross the FFI bound here.
19
    #[allow(improper_ctypes)]
20
    fn rust_fuzzer_test_input(input: &[u8]);
21
22
    fn LLVMFuzzerMutate(data: *mut u8, size: usize, max_size: usize) -> usize;
23
}
24
25
#[doc(hidden)]
26
#[export_name = "LLVMFuzzerTestOneInput"]
27
10.2k
pub fn test_input_wrap(data: *const u8, size: usize) -> i32 {
28
10.2k
    let test_input = ::std::panic::catch_unwind(|| unsafe {
29
10.2k
        let data_slice = ::std::slice::from_raw_parts(data, size);
30
10.2k
        rust_fuzzer_test_input(data_slice);
31
10.2k
    });
32
10.2k
    if test_input.err().is_some() {
33
        // hopefully the custom panic hook will be called before and abort the
34
        // process before the stack frames are unwinded.
35
0
        ::std::process::abort();
36
10.2k
    }
37
10.2k
    0
38
10.2k
}
39
40
#[doc(hidden)]
41
pub static RUST_LIBFUZZER_DEBUG_PATH: OnceCell<String> = OnceCell::new();
42
43
#[doc(hidden)]
44
#[export_name = "LLVMFuzzerInitialize"]
45
4
pub fn initialize(_argc: *const isize, _argv: *const *const *const u8) -> isize {
46
4
    // Registers a panic hook that aborts the process before unwinding.
47
4
    // It is useful to abort before unwinding so that the fuzzer will then be
48
4
    // able to analyse the process stack frames to tell different bugs appart.
49
4
    //
50
4
    // HACK / FIXME: it would be better to use `-C panic=abort` but it's currently
51
4
    // impossible to build code using compiler plugins with this flag.
52
4
    // We will be able to remove this code when
53
4
    // https://github.com/rust-lang/cargo/issues/5423 is fixed.
54
4
    let default_hook = ::std::panic::take_hook();
55
4
    ::std::panic::set_hook(Box::new(move |panic_info| {
56
0
        default_hook(panic_info);
57
0
        ::std::process::abort();
58
4
    }));
59
60
    // Initialize the `RUST_LIBFUZZER_DEBUG_PATH` cell with the path so it can be
61
    // reused with little overhead.
62
4
    if let Ok(path) = std::env::var("RUST_LIBFUZZER_DEBUG_PATH") {
63
0
        RUST_LIBFUZZER_DEBUG_PATH
64
0
            .set(path)
65
0
            .expect("Since this is initialize it is only called once so can never fail");
66
4
    }
67
4
    0
68
4
}
69
70
/// Define a fuzz target.
71
///
72
/// ## Example
73
///
74
/// This example takes a `&[u8]` slice and attempts to parse it. The parsing
75
/// might fail and return an `Err`, but it shouldn't ever panic or segfault.
76
///
77
/// ```no_run
78
/// #![no_main]
79
///
80
/// use libfuzzer_sys::fuzz_target;
81
///
82
/// // Note: `|input|` is short for `|input: &[u8]|`.
83
/// fuzz_target!(|input| {
84
///     let _result: Result<_, _> = my_crate::parse(input);
85
/// });
86
/// # mod my_crate { pub fn parse(_: &[u8]) -> Result<(), ()> { unimplemented!() } }
87
/// ```
88
///
89
/// ## Arbitrary Input Types
90
///
91
/// The input is a `&[u8]` slice by default, but you can take arbitrary input
92
/// types, as long as the type implements [the `arbitrary` crate's `Arbitrary`
93
/// trait](https://docs.rs/arbitrary/*/arbitrary/trait.Arbitrary.html) (which is
94
/// also re-exported as `libfuzzer_sys::arbitrary::Arbitrary` for convenience).
95
///
96
/// For example, if you wanted to take an arbitrary RGB color, you could do the
97
/// following:
98
///
99
/// ```no_run
100
/// #![no_main]
101
/// # mod foo {
102
///
103
/// use libfuzzer_sys::{arbitrary::{Arbitrary, Error, Unstructured}, fuzz_target};
104
///
105
/// #[derive(Debug)]
106
/// pub struct Rgb {
107
///     r: u8,
108
///     g: u8,
109
///     b: u8,
110
/// }
111
///
112
/// impl<'a> Arbitrary<'a> for Rgb {
113
///     fn arbitrary(raw: &mut Unstructured<'a>) -> Result<Self, Error> {
114
///         let mut buf = [0; 3];
115
///         raw.fill_buffer(&mut buf)?;
116
///         let r = buf[0];
117
///         let g = buf[1];
118
///         let b = buf[2];
119
///         Ok(Rgb { r, g, b })
120
///     }
121
/// }
122
///
123
/// // Write a fuzz target that works with RGB colors instead of raw bytes.
124
/// fuzz_target!(|color: Rgb| {
125
///     my_crate::convert_color(color);
126
/// });
127
/// # mod my_crate {
128
/// #     use super::Rgb;
129
/// #     pub fn convert_color(_: Rgb) {}
130
/// # }
131
/// # }
132
/// ```
133
///
134
/// You can also enable the `arbitrary` crate's custom derive via this crate's
135
/// `"arbitrary-derive"` cargo feature.
136
#[macro_export]
137
macro_rules! fuzz_target {
138
    (|$bytes:ident| $body:block) => {
139
        /// Auto-generated function
140
        #[no_mangle]
141
5.15k
        pub extern "C" fn rust_fuzzer_test_input($bytes: &[u8]) {
142
            // When `RUST_LIBFUZZER_DEBUG_PATH` is set, write the debug
143
            // formatting of the input to that file. This is only intended for
144
            // `cargo fuzz`'s use!
145
146
            // `RUST_LIBFUZZER_DEBUG_PATH` is set in initialization.
147
5.15k
            if let Some(path) = $crate::RUST_LIBFUZZER_DEBUG_PATH.get() {
148
                use std::io::Write;
149
0
                let mut file = std::fs::File::create(path)
150
0
                    .expect("failed to create `RUST_LIBFUZZER_DEBUG_PATH` file");
151
0
                writeln!(&mut file, "{:?}", $bytes)
152
0
                    .expect("failed to write to `RUST_LIBFUZZER_DEBUG_PATH` file");
153
0
                return;
154
5.15k
            }
155
5.15k
156
5.15k
            $body
157
5.15k
        }
158
5.15k
    };
159
5.15k
160
5.15k
    (|$data:ident: &[u8]| $body:block) => {
161
5.15k
        fuzz_target!(|$data| $body);
162
5.15k
    };
163
5.15k
164
5.15k
    (|$data:ident: $dty: ty| $body:block) => {
165
5.15k
        /// Auto-generated function
166
5.15k
        #[no_mangle]
167
5.15k
        pub extern "C" fn rust_fuzzer_test_input(bytes: &[u8]) {
168
5.15k
            use $crate::arbitrary::{Arbitrary, Unstructured};
169
5.15k
170
5.15k
            // Early exit if we don't have enough bytes for the `Arbitrary`
171
5.15k
            // implementation. This helps the fuzzer avoid exploring all the
172
5.15k
            // different not-enough-input-bytes paths inside the `Arbitrary`
173
5.15k
            // implementation. Additionally, it exits faster, letting the fuzzer
174
5.15k
            // get to longer inputs that actually lead to interesting executions
175
5.15k
            // quicker.
176
5.15k
            if bytes.len() < <$dty as Arbitrary>::size_hint(0).0 {
177
5.15k
                return;
178
5.15k
            }
179
5.15k
180
5.15k
            let mut u = Unstructured::new(bytes);
181
5.15k
            let data = <$dty as Arbitrary>::arbitrary_take_rest(u);
182
5.15k
183
5.15k
            // When `RUST_LIBFUZZER_DEBUG_PATH` is set, write the debug
184
5.15k
            // formatting of the input to that file. This is only intended for
185
5.15k
            // `cargo fuzz`'s use!
186
5.15k
187
5.15k
            // `RUST_LIBFUZZER_DEBUG_PATH` is set in initialization.
188
5.15k
            if let Some(path) = $crate::RUST_LIBFUZZER_DEBUG_PATH.get() {
189
5.15k
                use std::io::Write;
190
5.15k
                let mut file = std::fs::File::create(path)
191
5.15k
                    .expect("failed to create `RUST_LIBFUZZER_DEBUG_PATH` file");
192
5.15k
                (match data {
193
5.15k
                    Ok(data) => writeln!(&mut file, "{:#?}", data),
194
5.15k
                    Err(err) => writeln!(&mut file, "Arbitrary Error: {}", err),
195
5.15k
                })
196
5.15k
                .expect("failed to write to `RUST_LIBFUZZER_DEBUG_PATH` file");
197
5.15k
                return;
198
5.15k
            }
199
5.15k
200
5.15k
            let $data = match data {
201
5.15k
                Ok(d) => d,
202
5.15k
                Err(_) => return,
203
5.15k
            };
204
5.15k
205
5.15k
            $body
206
5.15k
        }
207
5.15k
    };
208
5.15k
}
209
5.15k
210
5.15k
/// Define a custom mutator.
211
5.15k
///
212
5.15k
/// This is optional, and libFuzzer will use its own, default mutation strategy
213
5.15k
/// if this is not provided.
214
5.15k
///
215
5.15k
/// You might consider using a custom mutator when your fuzz target is very
216
5.15k
/// particular about the shape of its input:
217
5.15k
///
218
5.15k
/// * You want to fuzz "deeper" than just the parser.
219
5.15k
/// * The input contains checksums that have to match the hash of some subset of
220
5.15k
///   the data or else the whole thing is invalid, and therefore mutating any of
221
5.15k
///   that subset means you need to recompute the checksums.
222
5.15k
/// * Small random changes to the input buffer make it invalid.
223
5.15k
///
224
5.15k
/// That is, a custom mutator is useful in similar situations where [a `T:
225
5.15k
/// Arbitrary` input type](macro.fuzz_target.html#arbitrary-input-types) is
226
5.15k
/// useful. Note that the two approaches are not mutually exclusive; you can use
227
5.15k
/// whichever is easier for your problem domain or both!
228
5.15k
///
229
5.15k
/// ## Implementation Contract
230
5.15k
///
231
5.15k
/// The original, unmodified input is given in `data[..size]`.
232
5.15k
///
233
5.15k
/// You must modify the data in place and return the new size.
234
5.15k
///
235
5.15k
/// The new size should not be greater than `max_size`. If this is not the case,
236
5.15k
/// then the `data` will be truncated to fit within `max_size`. Note that
237
5.15k
/// `max_size < size` is possible when shrinking test cases.
238
5.15k
///
239
5.15k
/// You must produce the same mutation given the same `seed`. Generally, when
240
5.15k
/// choosing what kind of mutation to make or where to mutate, you should start
241
5.15k
/// by creating a random number generator (RNG) that is seeded with the given
242
5.15k
/// `seed` and then consult the RNG whenever making a decision:
243
5.15k
///
244
5.15k
/// ```no_run
245
5.15k
/// #![no_main]
246
5.15k
///
247
5.15k
/// use rand::{rngs::StdRng, Rng, SeedableRng};
248
5.15k
///
249
5.15k
/// libfuzzer_sys::fuzz_mutator!(|data: &mut [u8], size: usize, max_size: usize, seed: u32| {
250
5.15k
///     let mut rng = StdRng::seed_from_u64(seed as u64);
251
5.15k
///
252
5.15k
/// #   let first_mutation = |_, _, _, _| todo!();
253
5.15k
/// #   let second_mutation = |_, _, _, _| todo!();
254
5.15k
/// #   let third_mutation = |_, _, _, _| todo!();
255
5.15k
/// #   let fourth_mutation = |_, _, _, _| todo!();
256
5.15k
///     // Choose which of our four supported kinds of mutations we want to make.
257
5.15k
///     match rng.gen_range(0..4) {
258
5.15k
///         0 => first_mutation(rng, data, size, max_size),
259
5.15k
///         1 => second_mutation(rng, data, size, max_size),
260
5.15k
///         2 => third_mutation(rng, data, size, max_size),
261
5.15k
///         3 => fourth_mutation(rng, data, size, max_size),
262
5.15k
///         _ => unreachable!()
263
5.15k
///     }
264
5.15k
/// });
265
5.15k
/// ```
266
5.15k
///
267
5.15k
/// ## Example: Compression
268
5.15k
///
269
5.15k
/// Consider a simple fuzz target that takes compressed data as input,
270
5.15k
/// decompresses it, and then asserts that the decompressed data doesn't begin
271
5.15k
/// with "boom". It is difficult for `libFuzzer` (or any other fuzzer) to crash
272
5.15k
/// this fuzz target because nearly all mutations it makes will invalidate the
273
5.15k
/// compression format. Therefore, we use a custom mutator that decompresses the
274
5.15k
/// raw input, mutates the decompressed data, and then recompresses it. This
275
5.15k
/// allows `libFuzzer` to quickly discover crashing inputs.
276
5.15k
///
277
5.15k
/// ```no_run
278
5.15k
/// #![no_main]
279
5.15k
///
280
5.15k
/// use flate2::{read::GzDecoder, write::GzEncoder, Compression};
281
5.15k
/// use libfuzzer_sys::{fuzz_mutator, fuzz_target};
282
5.15k
/// use std::io::{Read, Write};
283
5.15k
///
284
5.15k
/// fuzz_target!(|data: &[u8]| {
285
5.15k
///     // Decompress the input data and crash if it starts with "boom".
286
5.15k
///     if let Some(data) = decompress(data) {
287
5.15k
///         if data.starts_with(b"boom") {
288
5.15k
///             panic!();
289
5.15k
///         }
290
5.15k
///     }
291
5.15k
/// });
292
5.15k
///
293
5.15k
/// fuzz_mutator!(
294
5.15k
///     |data: &mut [u8], size: usize, max_size: usize, _seed: u32| {
295
5.15k
///         // Decompress the input data. If that fails, use a dummy value.
296
5.15k
///         let mut decompressed = decompress(&data[..size]).unwrap_or_else(|| b"hi".to_vec());
297
5.15k
///
298
5.15k
///         // Mutate the decompressed data with `libFuzzer`'s default mutator. Make
299
5.15k
///         // the `decompressed` vec's extra capacity available for insertion
300
5.15k
///         // mutations via `resize`.
301
5.15k
///         let len = decompressed.len();
302
5.15k
///         let cap = decompressed.capacity();
303
5.15k
///         decompressed.resize(cap, 0);
304
5.15k
///         let new_decompressed_size = libfuzzer_sys::fuzzer_mutate(&mut decompressed, len, cap);
305
5.15k
///
306
5.15k
///         // Recompress the mutated data.
307
5.15k
///         let compressed = compress(&decompressed[..new_decompressed_size]);
308
5.15k
///
309
5.15k
///         // Copy the recompressed mutated data into `data` and return the new size.
310
5.15k
///         let new_size = std::cmp::min(max_size, compressed.len());
311
5.15k
///         data[..new_size].copy_from_slice(&compressed[..new_size]);
312
5.15k
///         new_size
313
5.15k
///     }
314
5.15k
/// );
315
5.15k
///
316
5.15k
/// fn decompress(compressed_data: &[u8]) -> Option<Vec<u8>> {
317
5.15k
///     let mut decoder = GzDecoder::new(compressed_data);
318
5.15k
///     let mut decompressed = Vec::new();
319
5.15k
///     if decoder.read_to_end(&mut decompressed).is_ok() {
320
5.15k
///         Some(decompressed)
321
5.15k
///     } else {
322
5.15k
///         None
323
5.15k
///     }
324
5.15k
/// }
325
5.15k
///
326
5.15k
/// fn compress(data: &[u8]) -> Vec<u8> {
327
5.15k
///     let mut encoder = GzEncoder::new(Vec::new(), Compression::default());
328
5.15k
///     encoder
329
5.15k
///         .write_all(data)
330
5.15k
///         .expect("writing into a vec is infallible");
331
5.15k
///     encoder.finish().expect("writing into a vec is infallible")
332
5.15k
/// }
333
5.15k
/// ```
334
5.15k
///
335
5.15k
/// This example is inspired by [a similar example from the official `libFuzzer`
336
5.15k
/// docs](https://github.com/google/fuzzing/blob/master/docs/structure-aware-fuzzing.md#example-compression).
337
5.15k
///
338
5.15k
/// ## More Example Ideas
339
5.15k
///
340
5.15k
/// * A PNG custom mutator that decodes a PNG, mutates the image, and then
341
5.15k
/// re-encodes the mutated image as a new PNG.
342
5.15k
///
343
5.15k
/// * A [`serde`](https://serde.rs/) custom mutator that deserializes your
344
5.15k
///   structure, mutates it, and then reserializes it.
345
5.15k
///
346
5.15k
/// * A Wasm binary custom mutator that inserts, replaces, and removes a
347
5.15k
///   bytecode instruction in a function's body.
348
5.15k
///
349
5.15k
/// * An HTTP request custom mutator that inserts, replaces, and removes a
350
5.15k
///   header from an HTTP request.
351
5.15k
#[macro_export]
352
5.15k
macro_rules! fuzz_mutator {
353
5.15k
    (
354
5.15k
        |
355
5.15k
        $data:ident : &mut [u8] ,
356
5.15k
        $size:ident : usize ,
357
5.15k
        $max_size:ident : usize ,
358
5.15k
        $seed:ident : u32 $(,)*
359
5.15k
        |
360
5.15k
        $body:block
361
5.15k
    ) => {
362
5.15k
        /// Auto-generated function.
363
5.15k
        #[export_name = "LLVMFuzzerCustomMutator"]
364
5.15k
        pub fn rust_fuzzer_custom_mutator(
365
5.15k
            $data: *mut u8,
366
5.15k
            $size: usize,
367
5.15k
            $max_size: usize,
368
5.15k
            $seed: std::os::raw::c_uint,
369
5.15k
        ) -> usize {
370
5.15k
            // Depending on if we are growing or shrinking the test case, `size`
371
5.15k
            // might be larger or smaller than `max_size`. The `data`'s capacity
372
5.15k
            // is the maximum of the two.
373
5.15k
            let len = std::cmp::max($max_size, $size);
374
5.15k
            let $data: &mut [u8] = unsafe { std::slice::from_raw_parts_mut($data, len) };
375
5.15k
376
5.15k
            // `unsigned int` is generally a `u32`, but not on all targets. Do
377
5.15k
            // an infallible (and potentially lossy, but that's okay because it
378
5.15k
            // preserves determinism) conversion.
379
5.15k
            let $seed = $seed as u32;
380
5.15k
381
5.15k
            // Truncate the new size if it is larger than the max.
382
5.15k
            let new_size = { $body };
383
5.15k
            std::cmp::min(new_size, $max_size)
384
5.15k
        }
385
5.15k
    };
386
5.15k
}
387
5.15k
388
5.15k
/// The default `libFuzzer` mutator.
389
5.15k
///
390
5.15k
/// You generally don't have to use this at all unless you're defining a
391
5.15k
/// custom mutator with [the `fuzz_mutator!` macro][crate::fuzz_mutator].
392
5.15k
///
393
5.15k
/// Mutates `data[..size]` in place such that the mutated data is no larger than
394
5.15k
/// `max_size` and returns the new size of the mutated data.
395
5.15k
///
396
5.15k
/// To only allow shrinking mutations, make `max_size < size`.
397
5.15k
///
398
5.15k
/// To additionally allow mutations that grow the size of the data, make
399
5.15k
/// `max_size > size`.
400
5.15k
///
401
5.15k
/// Both `size` and `max_size` must be less than or equal to `data.len()`.
402
5.15k
///
403
5.15k
/// # Example
404
5.15k
///
405
5.15k
/// ```no_run
406
5.15k
/// // Create some data in a buffer.
407
5.15k
/// let mut data = vec![0; 128];
408
5.15k
/// data[..b"hello".len()].copy_from_slice(b"hello");
409
5.15k
///
410
5.15k
/// // Ask `libFuzzer` to mutate the data. By setting `max_size` to our buffer's
411
5.15k
/// // full length, we are allowing `libFuzzer` to perform mutations that grow
412
5.15k
/// // the size of the data, such as insertions.
413
5.15k
/// let size = b"hello".len();
414
5.15k
/// let max_size = data.len();
415
5.15k
/// let new_size = libfuzzer_sys::fuzzer_mutate(&mut data, size, max_size);
416
5.15k
///
417
5.15k
/// // Get the mutated data out of the buffer.
418
5.15k
/// let mutated_data = &data[..new_size];
419
5.15k
/// ```
420
5.15k
pub fn fuzzer_mutate(data: &mut [u8], size: usize, max_size: usize) -> usize {
421
0
    assert!(size <= data.len());
422
0
    assert!(max_size <= data.len());
423
0
    let new_size = unsafe { LLVMFuzzerMutate(data.as_mut_ptr(), size, max_size) };
424
0
    assert!(new_size <= data.len());
425
0
    new_size
426
0
}