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 
16 extern "C" {
17     // We do not actually cross the FFI bound here.
18     #[allow(improper_ctypes)]
rust_fuzzer_test_input(input: &[u8])19     fn rust_fuzzer_test_input(input: &[u8]);
20 }
21 
22 #[doc(hidden)]
23 #[export_name = "LLVMFuzzerTestOneInput"]
test_input_wrap(data: *const u8, size: usize) -> i3224 pub fn test_input_wrap(data: *const u8, size: usize) -> i32 {
25     let test_input = ::std::panic::catch_unwind(|| unsafe {
26         let data_slice = ::std::slice::from_raw_parts(data, size);
27         rust_fuzzer_test_input(data_slice);
28     });
29     if test_input.err().is_some() {
30         // hopefully the custom panic hook will be called before and abort the
31         // process before the stack frames are unwinded.
32         ::std::process::abort();
33     }
34     0
35 }
36 
37 #[doc(hidden)]
38 #[export_name = "LLVMFuzzerInitialize"]
initialize(_argc: *const isize, _argv: *const *const *const u8) -> isize39 pub fn initialize(_argc: *const isize, _argv: *const *const *const u8) -> isize {
40     // Registers a panic hook that aborts the process before unwinding.
41     // It is useful to abort before unwinding so that the fuzzer will then be
42     // able to analyse the process stack frames to tell different bugs appart.
43     //
44     // HACK / FIXME: it would be better to use `-C panic=abort` but it's currently
45     // impossible to build code using compiler plugins with this flag.
46     // We will be able to remove this code when
47     // https://github.com/rust-lang/cargo/issues/5423 is fixed.
48     let default_hook = ::std::panic::take_hook();
49     ::std::panic::set_hook(Box::new(move |panic_info| {
50         default_hook(panic_info);
51         ::std::process::abort();
52     }));
53     0
54 }
55 
56 /// Define a fuzz target.
57 ///
58 /// ## Example
59 ///
60 /// This example takes a `&[u8]` slice and attempts to parse it. The parsing
61 /// might fail and return an `Err`, but it shouldn't ever panic or segfault.
62 ///
63 /// ```no_run
64 /// #![no_main]
65 ///
66 /// use libfuzzer_sys::fuzz_target;
67 ///
68 /// // Note: `|input|` is short for `|input: &[u8]|`.
69 /// fuzz_target!(|input| {
70 ///     let _result: Result<_, _> = my_crate::parse(input);
71 /// });
72 /// # mod my_crate { pub fn parse(_: &[u8]) -> Result<(), ()> { unimplemented!() } }
73 /// ```
74 ///
75 /// ## Arbitrary Input Types
76 ///
77 /// The input is a `&[u8]` slice by default, but you can take arbitrary input
78 /// types, as long as the type implements [the `arbitrary` crate's `Arbitrary`
79 /// trait](https://docs.rs/arbitrary/*/arbitrary/trait.Arbitrary.html) (which is
80 /// also re-exported as `libfuzzer_sys::arbitrary::Arbitrary` for convenience).
81 ///
82 /// For example, if you wanted to take an arbitrary RGB color, you could do the
83 /// following:
84 ///
85 /// ```no_run
86 /// #![no_main]
87 ///
88 /// use libfuzzer_sys::{arbitrary::{Arbitrary, Unstructured}, fuzz_target};
89 ///
90 /// #[derive(Debug)]
91 /// pub struct Rgb {
92 ///     r: u8,
93 ///     g: u8,
94 ///     b: u8,
95 /// }
96 ///
97 /// impl Arbitrary for Rgb {
98 ///     fn arbitrary<U>(raw: &mut U) -> Result<Self, U::Error>
99 ///     where
100 ///         U: Unstructured + ?Sized
101 ///     {
102 ///         let mut buf = [0; 3];
103 ///         raw.fill_buffer(&mut buf)?;
104 ///         let r = buf[0];
105 ///         let g = buf[1];
106 ///         let b = buf[2];
107 ///         Ok(Rgb { r, g, b })
108 ///     }
109 /// }
110 ///
111 /// // Write a fuzz target that works with RGB colors instead of raw bytes.
112 /// fuzz_target!(|color: Rgb| {
113 ///     my_crate::convert_color(color);
114 /// });
115 /// # mod my_crate { fn convert_color(_: super::Rgb) {} }
116 #[macro_export]
117 macro_rules! fuzz_target {
118     (|$bytes:ident| $body:block) => {
119         #[no_mangle]
120         pub extern "C" fn rust_fuzzer_test_input($bytes: &[u8]) {
121             // When `RUST_LIBFUZZER_DEBUG_PATH` is set, write the debug
122             // formatting of the input to that file. This is only intended for
123             // `cargo fuzz`'s use!
124             if let Ok(path) = std::env::var("RUST_LIBFUZZER_DEBUG_PATH") {
125                 use std::io::Write;
126                 let mut file = std::fs::File::create(path)
127                     .expect("failed to create `RUST_LIBFUZZER_DEBUG_PATH` file");
128                 writeln!(&mut file, "{:?}", $bytes)
129                     .expect("failed to write to `RUST_LIBFUZZER_DEBUG_PATH` file");
130                 return;
131             }
132 
133             $body
134         }
135     };
136 
137     (|$data:ident: &[u8]| $body:block) => {
138         fuzz_target!(|$data| $body);
139     };
140 
141     (|$data:ident: $dty: ty| $body:block) => {
142         #[no_mangle]
143         pub extern "C" fn rust_fuzzer_test_input(bytes: &[u8]) {
144             use libfuzzer_sys::arbitrary::{Arbitrary, Unstructured};
145 
146             // Early exit if we don't have enough bytes for the `Arbitrary`
147             // implementation. This helps the fuzzer avoid exploring all the
148             // different not-enough-input-bytes paths inside the `Arbitrary`
149             // implementation. Additionally, it exits faster, letting the fuzzer
150             // get to longer inputs that actually lead to interesting executions
151             // quicker.
152             if bytes.len() < <$dty as Arbitrary>::size_hint(0).0 {
153                 return;
154             }
155 
156             let mut u = Unstructured::new(bytes);
157             let data = <$dty as Arbitrary>::arbitrary_take_rest(u);
158 
159             // When `RUST_LIBFUZZER_DEBUG_PATH` is set, write the debug
160             // formatting of the input to that file. This is only intended for
161             // `cargo fuzz`'s use!
162             if let Ok(path) = std::env::var("RUST_LIBFUZZER_DEBUG_PATH") {
163                 use std::io::Write;
164                 let mut file = std::fs::File::create(path)
165                     .expect("failed to create `RUST_LIBFUZZER_DEBUG_PATH` file");
166                 (match data {
167                     Ok(data) => writeln!(&mut file, "{:#?}", data),
168                     Err(err) => writeln!(&mut file, "Arbitrary Error: {}", err),
169                 })
170                 .expect("failed to write to `RUST_LIBFUZZER_DEBUG_PATH` file");
171                 return;
172             }
173 
174             let $data = match data {
175                 Ok(d) => d,
176                 Err(_) => return,
177             };
178 
179             $body
180         }
181     };
182 }
183