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