/rust/registry/src/index.crates.io-6f17d22bba15001f/libfuzzer-sys-0.4.7/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 | | /// Indicates whether the input should be kept in the corpus or rejected. This |
18 | | /// should be returned by your fuzz target. If your fuzz target does not return |
19 | | /// a value (i.e., returns `()`), then the input will be kept in the corpus. |
20 | 0 | #[derive(Debug)] |
21 | | pub enum Corpus { |
22 | | /// Keep the input in the corpus. |
23 | | Keep, |
24 | | |
25 | | /// Reject the input and do not keep it in the corpus. |
26 | | Reject, |
27 | | } |
28 | | |
29 | | impl From<()> for Corpus { |
30 | 0 | fn from(_: ()) -> Self { |
31 | 0 | Self::Keep |
32 | 0 | } |
33 | | } |
34 | | |
35 | | impl Corpus { |
36 | | #[doc(hidden)] |
37 | | /// Convert this Corpus result into the [integer codes used by |
38 | | /// `libFuzzer`](https://llvm.org/docs/LibFuzzer.html#rejecting-unwanted-inputs). |
39 | | /// This is -1 for reject, 0 for keep. |
40 | 0 | pub fn to_libfuzzer_code(self) -> i32 { |
41 | 0 | match self { |
42 | 0 | Corpus::Keep => 0, |
43 | 0 | Corpus::Reject => -1, |
44 | | } |
45 | 0 | } |
46 | | } |
47 | | |
48 | | extern "C" { |
49 | | // We do not actually cross the FFI bound here. |
50 | | #[allow(improper_ctypes)] |
51 | | fn rust_fuzzer_test_input(input: &[u8]) -> i32; |
52 | | |
53 | | fn LLVMFuzzerMutate(data: *mut u8, size: usize, max_size: usize) -> usize; |
54 | | } |
55 | | |
56 | | #[doc(hidden)] |
57 | | #[export_name = "LLVMFuzzerTestOneInput"] |
58 | 27.4k | pub fn test_input_wrap(data: *const u8, size: usize) -> i32 { |
59 | 27.4k | let test_input = ::std::panic::catch_unwind(|| unsafe { |
60 | 27.4k | let data_slice = ::std::slice::from_raw_parts(data, size); |
61 | 27.4k | rust_fuzzer_test_input(data_slice) |
62 | 27.4k | }); |
63 | 27.4k | |
64 | 27.4k | match test_input { |
65 | 27.4k | Ok(i) => i, |
66 | | Err(_) => { |
67 | | // hopefully the custom panic hook will be called before and abort the |
68 | | // process before the stack frames are unwinded. |
69 | 0 | ::std::process::abort(); |
70 | | } |
71 | | } |
72 | 27.4k | } |
73 | | |
74 | | #[doc(hidden)] |
75 | | pub static RUST_LIBFUZZER_DEBUG_PATH: OnceCell<String> = OnceCell::new(); |
76 | | |
77 | | #[doc(hidden)] |
78 | | #[export_name = "LLVMFuzzerInitialize"] |
79 | 32 | pub fn initialize(_argc: *const isize, _argv: *const *const *const u8) -> isize { |
80 | 32 | // Registers a panic hook that aborts the process before unwinding. |
81 | 32 | // It is useful to abort before unwinding so that the fuzzer will then be |
82 | 32 | // able to analyse the process stack frames to tell different bugs appart. |
83 | 32 | // |
84 | 32 | // HACK / FIXME: it would be better to use `-C panic=abort` but it's currently |
85 | 32 | // impossible to build code using compiler plugins with this flag. |
86 | 32 | // We will be able to remove this code when |
87 | 32 | // https://github.com/rust-lang/cargo/issues/5423 is fixed. |
88 | 32 | let default_hook = ::std::panic::take_hook(); |
89 | 32 | ::std::panic::set_hook(Box::new(move |panic_info| { |
90 | 0 | default_hook(panic_info); |
91 | 0 | ::std::process::abort(); |
92 | 32 | })); |
93 | | |
94 | | // Initialize the `RUST_LIBFUZZER_DEBUG_PATH` cell with the path so it can be |
95 | | // reused with little overhead. |
96 | 32 | if let Ok(path) = std::env::var("RUST_LIBFUZZER_DEBUG_PATH") { |
97 | 0 | RUST_LIBFUZZER_DEBUG_PATH |
98 | 0 | .set(path) |
99 | 0 | .expect("Since this is initialize it is only called once so can never fail"); |
100 | 32 | } |
101 | 32 | 0 |
102 | 32 | } |
103 | | |
104 | | /// Define a fuzz target. |
105 | | /// |
106 | | /// ## Example |
107 | | /// |
108 | | /// This example takes a `&[u8]` slice and attempts to parse it. The parsing |
109 | | /// might fail and return an `Err`, but it shouldn't ever panic or segfault. |
110 | | /// |
111 | | /// ```no_run |
112 | | /// #![no_main] |
113 | | /// |
114 | | /// use libfuzzer_sys::fuzz_target; |
115 | | /// |
116 | | /// // Note: `|input|` is short for `|input: &[u8]|`. |
117 | | /// fuzz_target!(|input| { |
118 | | /// let _result: Result<_, _> = my_crate::parse(input); |
119 | | /// }); |
120 | | /// # mod my_crate { pub fn parse(_: &[u8]) -> Result<(), ()> { unimplemented!() } } |
121 | | /// ``` |
122 | | /// |
123 | | /// ## Rejecting Inputs |
124 | | /// |
125 | | /// It may be desirable to reject some inputs, i.e. to not add them to the |
126 | | /// corpus. |
127 | | /// |
128 | | /// For example, when fuzzing an API consisting of parsing and other logic, |
129 | | /// one may want to allow only those inputs into the corpus that parse |
130 | | /// successfully. To indicate whether an input should be kept in or rejected |
131 | | /// from the corpus, return either [Corpus::Keep] or [Corpus::Reject] from your |
132 | | /// fuzz target. The default behavior (e.g. if `()` is returned) is to keep the |
133 | | /// input in the corpus. |
134 | | /// |
135 | | /// For example: |
136 | | /// |
137 | | /// ```no_run |
138 | | /// #![no_main] |
139 | | /// |
140 | | /// use libfuzzer_sys::{Corpus, fuzz_target}; |
141 | | /// |
142 | | /// fuzz_target!(|input: String| -> Corpus { |
143 | | /// let parts: Vec<&str> = input.splitn(2, '=').collect(); |
144 | | /// if parts.len() != 2 { |
145 | | /// return Corpus::Reject; |
146 | | /// } |
147 | | /// |
148 | | /// let key = parts[0]; |
149 | | /// let value = parts[1]; |
150 | | /// let _result: Result<_, _> = my_crate::parse(key, value); |
151 | | /// Corpus::Keep |
152 | | /// }); |
153 | | /// # mod my_crate { pub fn parse(_key: &str, _value: &str) -> Result<(), ()> { unimplemented!() } } |
154 | | /// ``` |
155 | | /// |
156 | | /// ## Arbitrary Input Types |
157 | | /// |
158 | | /// The input is a `&[u8]` slice by default, but you can take arbitrary input |
159 | | /// types, as long as the type implements [the `arbitrary` crate's `Arbitrary` |
160 | | /// trait](https://docs.rs/arbitrary/*/arbitrary/trait.Arbitrary.html) (which is |
161 | | /// also re-exported as `libfuzzer_sys::arbitrary::Arbitrary` for convenience). |
162 | | /// |
163 | | /// For example, if you wanted to take an arbitrary RGB color, you could do the |
164 | | /// following: |
165 | | /// |
166 | | /// ```no_run |
167 | | /// #![no_main] |
168 | | /// # mod foo { |
169 | | /// |
170 | | /// use libfuzzer_sys::{arbitrary::{Arbitrary, Error, Unstructured}, fuzz_target}; |
171 | | /// |
172 | | /// #[derive(Debug)] |
173 | | /// pub struct Rgb { |
174 | | /// r: u8, |
175 | | /// g: u8, |
176 | | /// b: u8, |
177 | | /// } |
178 | | /// |
179 | | /// impl<'a> Arbitrary<'a> for Rgb { |
180 | | /// fn arbitrary(raw: &mut Unstructured<'a>) -> Result<Self, Error> { |
181 | | /// let mut buf = [0; 3]; |
182 | | /// raw.fill_buffer(&mut buf)?; |
183 | | /// let r = buf[0]; |
184 | | /// let g = buf[1]; |
185 | | /// let b = buf[2]; |
186 | | /// Ok(Rgb { r, g, b }) |
187 | | /// } |
188 | | /// } |
189 | | /// |
190 | | /// // Write a fuzz target that works with RGB colors instead of raw bytes. |
191 | | /// fuzz_target!(|color: Rgb| { |
192 | | /// my_crate::convert_color(color); |
193 | | /// }); |
194 | | /// # mod my_crate { |
195 | | /// # use super::Rgb; |
196 | | /// # pub fn convert_color(_: Rgb) {} |
197 | | /// # } |
198 | | /// # } |
199 | | /// ``` |
200 | | /// |
201 | | /// You can also enable the `arbitrary` crate's custom derive via this crate's |
202 | | /// `"arbitrary-derive"` cargo feature. |
203 | | #[macro_export] |
204 | | macro_rules! fuzz_target { |
205 | | (|$bytes:ident| $body:expr) => { |
206 | | const _: () = { |
207 | | /// Auto-generated function |
208 | | #[no_mangle] |
209 | 651 | pub extern "C" fn rust_fuzzer_test_input(bytes: &[u8]) -> i32 { |
210 | | // When `RUST_LIBFUZZER_DEBUG_PATH` is set, write the debug |
211 | | // formatting of the input to that file. This is only intended for |
212 | | // `cargo fuzz`'s use! |
213 | | |
214 | | // `RUST_LIBFUZZER_DEBUG_PATH` is set in initialization. |
215 | 651 | if let Some(path) = $crate::RUST_LIBFUZZER_DEBUG_PATH.get() { |
216 | | use std::io::Write; |
217 | 0 | let mut file = std::fs::File::create(path) |
218 | 0 | .expect("failed to create `RUST_LIBFUZZER_DEBUG_PATH` file"); |
219 | 0 | writeln!(&mut file, "{:?}", bytes) |
220 | 0 | .expect("failed to write to `RUST_LIBFUZZER_DEBUG_PATH` file"); |
221 | 0 | return 0; |
222 | 651 | } |
223 | 651 | |
224 | 651 | __libfuzzer_sys_run(bytes); |
225 | 651 | 0 |
226 | 651 | } |
227 | | |
228 | | // Split out the actual fuzzer into a separate function which is |
229 | | // tagged as never being inlined. This ensures that if the fuzzer |
230 | | // panics there's at least one stack frame which is named uniquely |
231 | | // according to this specific fuzzer that this is embedded within. |
232 | | // |
233 | | // Systems like oss-fuzz try to deduplicate crashes and without this |
234 | | // panics in separate fuzzers can accidentally appear the same |
235 | | // because each fuzzer will have a function called |
236 | | // `rust_fuzzer_test_input`. By using a normal Rust function here |
237 | | // it's named something like `the_fuzzer_name::_::__libfuzzer_sys_run` which should |
238 | | // ideally help prevent oss-fuzz from deduplicate fuzz bugs across |
239 | | // distinct targets accidentally. |
240 | | #[inline(never)] |
241 | 26.6k | fn __libfuzzer_sys_run($bytes: &[u8]) { |
242 | 777 | $body |
243 | 26.6k | } watchdog::_::__libfuzzer_sys_run Line | Count | Source | 241 | 651 | fn __libfuzzer_sys_run($bytes: &[u8]) { | 242 | | $body | 243 | 651 | } |
serial::_::__libfuzzer_sys_run Line | Count | Source | 241 | 568 | fn __libfuzzer_sys_run($bytes: &[u8]) { | 242 | | $body | 243 | 568 | } |
linux_loader_cmdline::_::__libfuzzer_sys_run Line | Count | Source | 241 | 538 | fn __libfuzzer_sys_run($bytes: &[u8]) { | 242 | | $body | 243 | 538 | } |
http_api::_::__libfuzzer_sys_run Line | Count | Source | 241 | 17.3k | fn __libfuzzer_sys_run($bytes: &[u8]) { | 242 | | $body | 243 | 17.3k | } |
qcow::_::__libfuzzer_sys_run Line | Count | Source | 241 | 1.66k | fn __libfuzzer_sys_run($bytes: &[u8]) { | 242 | | $body | 243 | 1.66k | } |
iommu::_::__libfuzzer_sys_run Line | Count | Source | 241 | 900 | fn __libfuzzer_sys_run($bytes: &[u8]) { | 242 | | $body | 243 | 900 | } |
linux_loader::_::__libfuzzer_sys_run Line | Count | Source | 241 | 777 | fn __libfuzzer_sys_run($bytes: &[u8]) { | 242 | 777 | $body | 243 | 777 | } |
pmem::_::__libfuzzer_sys_run Line | Count | Source | 241 | 679 | fn __libfuzzer_sys_run($bytes: &[u8]) { | 242 | | $body | 243 | 679 | } |
cmos::_::__libfuzzer_sys_run Line | Count | Source | 241 | 298 | fn __libfuzzer_sys_run($bytes: &[u8]) { | 242 | | $body | 243 | 298 | } |
rng::_::__libfuzzer_sys_run Line | Count | Source | 241 | 439 | fn __libfuzzer_sys_run($bytes: &[u8]) { | 242 | | $body | 243 | 439 | } |
net::_::__libfuzzer_sys_run Line | Count | Source | 241 | 632 | fn __libfuzzer_sys_run($bytes: &[u8]) { | 242 | | $body | 243 | 632 | } |
mem::_::__libfuzzer_sys_run Line | Count | Source | 241 | 684 | fn __libfuzzer_sys_run($bytes: &[u8]) { | 242 | | $body | 243 | 684 | } |
vhdx::_::__libfuzzer_sys_run Line | Count | Source | 241 | 431 | fn __libfuzzer_sys_run($bytes: &[u8]) { | 242 | | $body | 243 | 431 | } |
block::_::__libfuzzer_sys_run Line | Count | Source | 241 | 758 | fn __libfuzzer_sys_run($bytes: &[u8]) { | 242 | | $body | 243 | 758 | } |
console::_::__libfuzzer_sys_run Line | Count | Source | 241 | 515 | fn __libfuzzer_sys_run($bytes: &[u8]) { | 242 | | $body | 243 | 515 | } |
balloon::_::__libfuzzer_sys_run Line | Count | Source | 241 | 560 | fn __libfuzzer_sys_run($bytes: &[u8]) { | 242 | | $body | 243 | 560 | } |
|
244 | | }; |
245 | | }; |
246 | | |
247 | | (|$data:ident: &[u8]| $body:expr) => { |
248 | | $crate::fuzz_target!(|$data| $body); |
249 | | }; |
250 | | |
251 | | (|$data:ident: $dty:ty| $body:expr) => { |
252 | | $crate::fuzz_target!(|$data: $dty| -> () { $body }); |
253 | | }; |
254 | | |
255 | | (|$data:ident: $dty:ty| -> $rty:ty $body:block) => { |
256 | | const _: () = { |
257 | | /// Auto-generated function |
258 | | #[no_mangle] |
259 | | pub extern "C" fn rust_fuzzer_test_input(bytes: &[u8]) -> i32 { |
260 | | use $crate::arbitrary::{Arbitrary, Unstructured}; |
261 | | |
262 | | // Early exit if we don't have enough bytes for the `Arbitrary` |
263 | | // implementation. This helps the fuzzer avoid exploring all the |
264 | | // different not-enough-input-bytes paths inside the `Arbitrary` |
265 | | // implementation. Additionally, it exits faster, letting the fuzzer |
266 | | // get to longer inputs that actually lead to interesting executions |
267 | | // quicker. |
268 | | if bytes.len() < <$dty as Arbitrary>::size_hint(0).0 { |
269 | | return -1; |
270 | | } |
271 | | |
272 | | let mut u = Unstructured::new(bytes); |
273 | | let data = <$dty as Arbitrary>::arbitrary_take_rest(u); |
274 | | |
275 | | // When `RUST_LIBFUZZER_DEBUG_PATH` is set, write the debug |
276 | | // formatting of the input to that file. This is only intended for |
277 | | // `cargo fuzz`'s use! |
278 | | |
279 | | // `RUST_LIBFUZZER_DEBUG_PATH` is set in initialization. |
280 | | if let Some(path) = $crate::RUST_LIBFUZZER_DEBUG_PATH.get() { |
281 | | use std::io::Write; |
282 | | let mut file = std::fs::File::create(path) |
283 | | .expect("failed to create `RUST_LIBFUZZER_DEBUG_PATH` file"); |
284 | | (match data { |
285 | | Ok(data) => writeln!(&mut file, "{:#?}", data), |
286 | | Err(err) => writeln!(&mut file, "Arbitrary Error: {}", err), |
287 | | }) |
288 | | .expect("failed to write to `RUST_LIBFUZZER_DEBUG_PATH` file"); |
289 | | return -1; |
290 | | } |
291 | | |
292 | | let data = match data { |
293 | | Ok(d) => d, |
294 | | Err(_) => return -1, |
295 | | }; |
296 | | |
297 | | let result = ::libfuzzer_sys::Corpus::from(__libfuzzer_sys_run(data)); |
298 | | result.to_libfuzzer_code() |
299 | | } |
300 | | |
301 | | // See above for why this is split to a separate function. |
302 | | #[inline(never)] |
303 | | fn __libfuzzer_sys_run($data: $dty) -> $rty { |
304 | | $body |
305 | | } |
306 | | }; |
307 | | }; |
308 | | } |
309 | | |
310 | | /// Define a custom mutator. |
311 | | /// |
312 | | /// This is optional, and libFuzzer will use its own, default mutation strategy |
313 | | /// if this is not provided. |
314 | | /// |
315 | | /// You might consider using a custom mutator when your fuzz target is very |
316 | | /// particular about the shape of its input: |
317 | | /// |
318 | | /// * You want to fuzz "deeper" than just the parser. |
319 | | /// * The input contains checksums that have to match the hash of some subset of |
320 | | /// the data or else the whole thing is invalid, and therefore mutating any of |
321 | | /// that subset means you need to recompute the checksums. |
322 | | /// * Small random changes to the input buffer make it invalid. |
323 | | /// |
324 | | /// That is, a custom mutator is useful in similar situations where [a `T: |
325 | | /// Arbitrary` input type](macro.fuzz_target.html#arbitrary-input-types) is |
326 | | /// useful. Note that the two approaches are not mutually exclusive; you can use |
327 | | /// whichever is easier for your problem domain or both! |
328 | | /// |
329 | | /// ## Implementation Contract |
330 | | /// |
331 | | /// The original, unmodified input is given in `data[..size]`. |
332 | | /// |
333 | | /// You must modify the data in place and return the new size. |
334 | | /// |
335 | | /// The new size should not be greater than `max_size`. If this is not the case, |
336 | | /// then the `data` will be truncated to fit within `max_size`. Note that |
337 | | /// `max_size < size` is possible when shrinking test cases. |
338 | | /// |
339 | | /// You must produce the same mutation given the same `seed`. Generally, when |
340 | | /// choosing what kind of mutation to make or where to mutate, you should start |
341 | | /// by creating a random number generator (RNG) that is seeded with the given |
342 | | /// `seed` and then consult the RNG whenever making a decision: |
343 | | /// |
344 | | /// ```no_run |
345 | | /// #![no_main] |
346 | | /// |
347 | | /// use rand::{rngs::StdRng, Rng, SeedableRng}; |
348 | | /// |
349 | | /// libfuzzer_sys::fuzz_mutator!(|data: &mut [u8], size: usize, max_size: usize, seed: u32| { |
350 | | /// let mut rng = StdRng::seed_from_u64(seed as u64); |
351 | | /// |
352 | | /// # let first_mutation = |_, _, _, _| todo!(); |
353 | | /// # let second_mutation = |_, _, _, _| todo!(); |
354 | | /// # let third_mutation = |_, _, _, _| todo!(); |
355 | | /// # let fourth_mutation = |_, _, _, _| todo!(); |
356 | | /// // Choose which of our four supported kinds of mutations we want to make. |
357 | | /// match rng.gen_range(0..4) { |
358 | | /// 0 => first_mutation(rng, data, size, max_size), |
359 | | /// 1 => second_mutation(rng, data, size, max_size), |
360 | | /// 2 => third_mutation(rng, data, size, max_size), |
361 | | /// 3 => fourth_mutation(rng, data, size, max_size), |
362 | | /// _ => unreachable!() |
363 | | /// } |
364 | | /// }); |
365 | | /// ``` |
366 | | /// |
367 | | /// ## Example: Compression |
368 | | /// |
369 | | /// Consider a simple fuzz target that takes compressed data as input, |
370 | | /// decompresses it, and then asserts that the decompressed data doesn't begin |
371 | | /// with "boom". It is difficult for `libFuzzer` (or any other fuzzer) to crash |
372 | | /// this fuzz target because nearly all mutations it makes will invalidate the |
373 | | /// compression format. Therefore, we use a custom mutator that decompresses the |
374 | | /// raw input, mutates the decompressed data, and then recompresses it. This |
375 | | /// allows `libFuzzer` to quickly discover crashing inputs. |
376 | | /// |
377 | | /// ```no_run |
378 | | /// #![no_main] |
379 | | /// |
380 | | /// use flate2::{read::GzDecoder, write::GzEncoder, Compression}; |
381 | | /// use libfuzzer_sys::{fuzz_mutator, fuzz_target}; |
382 | | /// use std::io::{Read, Write}; |
383 | | /// |
384 | | /// fuzz_target!(|data: &[u8]| { |
385 | | /// // Decompress the input data and crash if it starts with "boom". |
386 | | /// if let Some(data) = decompress(data) { |
387 | | /// if data.starts_with(b"boom") { |
388 | | /// panic!(); |
389 | | /// } |
390 | | /// } |
391 | | /// }); |
392 | | /// |
393 | | /// fuzz_mutator!( |
394 | | /// |data: &mut [u8], size: usize, max_size: usize, _seed: u32| { |
395 | | /// // Decompress the input data. If that fails, use a dummy value. |
396 | | /// let mut decompressed = decompress(&data[..size]).unwrap_or_else(|| b"hi".to_vec()); |
397 | | /// |
398 | | /// // Mutate the decompressed data with `libFuzzer`'s default mutator. Make |
399 | | /// // the `decompressed` vec's extra capacity available for insertion |
400 | | /// // mutations via `resize`. |
401 | | /// let len = decompressed.len(); |
402 | | /// let cap = decompressed.capacity(); |
403 | | /// decompressed.resize(cap, 0); |
404 | | /// let new_decompressed_size = libfuzzer_sys::fuzzer_mutate(&mut decompressed, len, cap); |
405 | | /// |
406 | | /// // Recompress the mutated data. |
407 | | /// let compressed = compress(&decompressed[..new_decompressed_size]); |
408 | | /// |
409 | | /// // Copy the recompressed mutated data into `data` and return the new size. |
410 | | /// let new_size = std::cmp::min(max_size, compressed.len()); |
411 | | /// data[..new_size].copy_from_slice(&compressed[..new_size]); |
412 | | /// new_size |
413 | | /// } |
414 | | /// ); |
415 | | /// |
416 | | /// fn decompress(compressed_data: &[u8]) -> Option<Vec<u8>> { |
417 | | /// let mut decoder = GzDecoder::new(compressed_data); |
418 | | /// let mut decompressed = Vec::new(); |
419 | | /// if decoder.read_to_end(&mut decompressed).is_ok() { |
420 | | /// Some(decompressed) |
421 | | /// } else { |
422 | | /// None |
423 | | /// } |
424 | | /// } |
425 | | /// |
426 | | /// fn compress(data: &[u8]) -> Vec<u8> { |
427 | | /// let mut encoder = GzEncoder::new(Vec::new(), Compression::default()); |
428 | | /// encoder |
429 | | /// .write_all(data) |
430 | | /// .expect("writing into a vec is infallible"); |
431 | | /// encoder.finish().expect("writing into a vec is infallible") |
432 | | /// } |
433 | | /// ``` |
434 | | /// |
435 | | /// This example is inspired by [a similar example from the official `libFuzzer` |
436 | | /// docs](https://github.com/google/fuzzing/blob/master/docs/structure-aware-fuzzing.md#example-compression). |
437 | | /// |
438 | | /// ## More Example Ideas |
439 | | /// |
440 | | /// * A PNG custom mutator that decodes a PNG, mutates the image, and then |
441 | | /// re-encodes the mutated image as a new PNG. |
442 | | /// |
443 | | /// * A [`serde`](https://serde.rs/) custom mutator that deserializes your |
444 | | /// structure, mutates it, and then reserializes it. |
445 | | /// |
446 | | /// * A Wasm binary custom mutator that inserts, replaces, and removes a |
447 | | /// bytecode instruction in a function's body. |
448 | | /// |
449 | | /// * An HTTP request custom mutator that inserts, replaces, and removes a |
450 | | /// header from an HTTP request. |
451 | | #[macro_export] |
452 | | macro_rules! fuzz_mutator { |
453 | | ( |
454 | | | |
455 | | $data:ident : &mut [u8] , |
456 | | $size:ident : usize , |
457 | | $max_size:ident : usize , |
458 | | $seed:ident : u32 $(,)* |
459 | | | |
460 | | $body:block |
461 | | ) => { |
462 | | /// Auto-generated function. |
463 | | #[export_name = "LLVMFuzzerCustomMutator"] |
464 | | pub fn rust_fuzzer_custom_mutator( |
465 | | $data: *mut u8, |
466 | | $size: usize, |
467 | | $max_size: usize, |
468 | | $seed: std::os::raw::c_uint, |
469 | | ) -> usize { |
470 | | // Depending on if we are growing or shrinking the test case, `size` |
471 | | // might be larger or smaller than `max_size`. The `data`'s capacity |
472 | | // is the maximum of the two. |
473 | | let len = std::cmp::max($max_size, $size); |
474 | | let $data: &mut [u8] = unsafe { std::slice::from_raw_parts_mut($data, len) }; |
475 | | |
476 | | // `unsigned int` is generally a `u32`, but not on all targets. Do |
477 | | // an infallible (and potentially lossy, but that's okay because it |
478 | | // preserves determinism) conversion. |
479 | | let $seed = $seed as u32; |
480 | | |
481 | | // Truncate the new size if it is larger than the max. |
482 | | let new_size = { $body }; |
483 | | std::cmp::min(new_size, $max_size) |
484 | | } |
485 | | }; |
486 | | } |
487 | | |
488 | | /// The default `libFuzzer` mutator. |
489 | | /// |
490 | | /// You generally don't have to use this at all unless you're defining a |
491 | | /// custom mutator with [the `fuzz_mutator!` macro][crate::fuzz_mutator]. |
492 | | /// |
493 | | /// Mutates `data[..size]` in place such that the mutated data is no larger than |
494 | | /// `max_size` and returns the new size of the mutated data. |
495 | | /// |
496 | | /// To only allow shrinking mutations, make `max_size < size`. |
497 | | /// |
498 | | /// To additionally allow mutations that grow the size of the data, make |
499 | | /// `max_size > size`. |
500 | | /// |
501 | | /// Both `size` and `max_size` must be less than or equal to `data.len()`. |
502 | | /// |
503 | | /// # Example |
504 | | /// |
505 | | /// ```no_run |
506 | | /// // Create some data in a buffer. |
507 | | /// let mut data = vec![0; 128]; |
508 | | /// data[..b"hello".len()].copy_from_slice(b"hello"); |
509 | | /// |
510 | | /// // Ask `libFuzzer` to mutate the data. By setting `max_size` to our buffer's |
511 | | /// // full length, we are allowing `libFuzzer` to perform mutations that grow |
512 | | /// // the size of the data, such as insertions. |
513 | | /// let size = b"hello".len(); |
514 | | /// let max_size = data.len(); |
515 | | /// let new_size = libfuzzer_sys::fuzzer_mutate(&mut data, size, max_size); |
516 | | /// |
517 | | /// // Get the mutated data out of the buffer. |
518 | | /// let mutated_data = &data[..new_size]; |
519 | | /// ``` |
520 | 0 | pub fn fuzzer_mutate(data: &mut [u8], size: usize, max_size: usize) -> usize { |
521 | 0 | assert!(size <= data.len()); |
522 | 0 | assert!(max_size <= data.len()); |
523 | 0 | let new_size = unsafe { LLVMFuzzerMutate(data.as_mut_ptr(), size, max_size) }; |
524 | 0 | assert!(new_size <= data.len()); |
525 | 0 | new_size |
526 | 0 | } |