/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 | } |