1 //! Custom fuzz input mutators.
2 //!
3 //! The functions in this module are intended to be used with [the
4 //! `libfuzzer_sys::fuzz_mutator!` macro][fuzz-mutator].
5 //!
6 //! [fuzz-mutator]: https://docs.rs/libfuzzer-sys/latest/libfuzzer_sys/macro.fuzz_mutator.html
7 
8 use arbitrary::{Arbitrary, Unstructured};
9 use std::sync::Arc;
10 
11 /// Use [`wasm-mutate`][wasm-mutate] to mutate a fuzz input.
12 ///
13 /// [wasm-mutate]: https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wasm-mutate
wasm_mutate( data: &mut [u8], size: usize, max_size: usize, seed: u32, libfuzzer_mutate: fn(data: &mut [u8], size: usize, max_size: usize) -> usize, ) -> usize14 pub fn wasm_mutate(
15     data: &mut [u8],
16     size: usize,
17     max_size: usize,
18     seed: u32,
19     libfuzzer_mutate: fn(data: &mut [u8], size: usize, max_size: usize) -> usize,
20 ) -> usize {
21     const MUTATION_FUEL: u64 = 100;
22     const MUTATION_ITERS: usize = 100;
23 
24     let wasm = &data[..size];
25 
26     if wasmparser::validate(wasm).is_ok() {
27         let mut wasm_mutate = wasm_mutate::WasmMutate::default();
28         wasm_mutate
29             .seed(seed.into())
30             .fuel(MUTATION_FUEL)
31             .reduce(max_size < size)
32             .raw_mutate_func(Some(Arc::new(move |data, max_size| {
33                 let len = data.len();
34 
35                 // The given max could be very large, so clamp it to no more
36                 // than `len * 2` in any single, given mutation. This way we
37                 // don't over-allocate a bunch of space.
38                 let max_size = std::cmp::min(max_size, len * 2);
39                 // Also, the max must always be greater than zero (`libfuzzer`
40                 // asserts this).
41                 let max_size = std::cmp::max(max_size, 1);
42 
43                 // Make sure we have capacity in case `libfuzzer` decides to
44                 // grow this data.
45                 if max_size > len {
46                     data.resize(max_size, 0);
47                 }
48 
49                 // Finally, have `libfuzzer` mutate the data!
50                 let new_len = libfuzzer_mutate(data, len, max_size);
51 
52                 // Resize the data to the mutated size, releasing any extra
53                 // capacity that we don't need anymore.
54                 data.resize(new_len, 0);
55                 data.shrink_to_fit();
56 
57                 Ok(())
58             })));
59 
60         let wasm = wasm.to_vec();
61         let mutations = wasm_mutate.run(&wasm);
62         if let Ok(mutations) = mutations {
63             for mutation in mutations.take(MUTATION_ITERS) {
64                 if let Ok(mutated_wasm) = mutation {
65                     if mutated_wasm.len() <= max_size {
66                         data[..mutated_wasm.len()].copy_from_slice(&mutated_wasm);
67                         return mutated_wasm.len();
68                     }
69                 }
70             }
71         }
72     }
73 
74     // If we can't mutate the input because it isn't valid Wasm or `wasm-mutate`
75     // otherwise fails, try to use `wasm-smith` to generate a new, arbitrary
76     // Wasm module that fits within the max-size limit.
77     let mut u = Unstructured::new(&data[..max_size]);
78     if let Ok(module) = wasm_smith::Module::arbitrary(&mut u) {
79         let wasm = module.to_bytes();
80         if wasm.len() <= max_size {
81             data[..wasm.len()].copy_from_slice(&wasm);
82             return wasm.len();
83         }
84     }
85 
86     // Otherwise, try to return an empty Wasm module:
87     //
88     // ```
89     // (module)
90     // ```
91     static EMPTY_WASM: &[u8] = &[0x00, b'a', b's', b'm', 0x01, 0x00, 0x00, 0x00];
92     if EMPTY_WASM.len() <= max_size {
93         data[..EMPTY_WASM.len()].copy_from_slice(EMPTY_WASM);
94         return EMPTY_WASM.len();
95     }
96 
97     // If the max size is even smaller than an empty Wasm module, then just let
98     // `libfuzzer` mutate the data.
99     libfuzzer_mutate(data, size, max_size)
100 }
101