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