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
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
/*!

`BufRng` is a "random" number generator that simply yields pre-determined values
from a buffer, and yields `0`s once the buffer is exhausted.

<div align="center">

  <p>⚠⚠⚠</p>

  <p><strong>This RNG is not suitable for anything other than testing and
  fuzzing! It is not suitable for cryptography! It is not suitable for
  generating pseudo-random numbers!</strong></p>

  <p>⚠⚠⚠</p>

</div>

## Why?

`BufRng` is useful for reinterpreting raw input bytes from
[libFuzzer](https://rust-fuzz.github.io/book/cargo-fuzz.html) or
[AFL](https://rust-fuzz.github.io/book/afl.html) as an RNG that is used with
structure-aware test case generators (e.g.
[`quickcheck::Arbitrary`](https://docs.rs/quickcheck/0.9.0/quickcheck/trait.Arbitrary.html)). This
combines the power of coverage-guided fuzzing with structure-aware fuzzing.

## Example

Let's say we are developing a crate to convert back and forth between RGB and
HSL color representations.

First, we can implement `quickcheck::Arbitrary` for our color types to get
structure-aware test case generators. Then, we can use these with `quickcheck`'s
own test runner infrastructure to assert various properties about our code (such
as it never panics, or that RGB -> HSL -> RGB is the identity function) and
`quickcheck` will generate random instances of `Rgb` and `Hsl` to check this
property against.

```no_run
/// A color represented with RGB.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Rgb {
    pub r: u8,
    pub g: u8,
    pub b: u8,
}

impl Rgb {
    pub fn to_hsl(&self) -> Hsl {
        // ...
#       unimplemented!()
    }
}

/// A color represented with HSL.
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Hsl {
    pub h: f64,
    pub s: f64,
    pub l: f64,
}

impl Hsl {
    pub fn to_rgb(&self) -> Rgb {
        // ...
#       unimplemented!()
    }
}

// Implementations of `quickcheck::Arbitrary` to create structure-aware test
// case generators for `Rgb` and `Hsl`.

use rand::prelude::*;
use quickcheck::{Arbitrary, Gen};

impl Arbitrary for Rgb {
    fn arbitrary<G: Gen>(g: &mut G) -> Self {
        Rgb {
            r: g.gen(),
            g: g.gen(),
            b: g.gen(),
        }
    }
}

impl Arbitrary for Hsl {
    fn arbitrary<G: Gen>(g: &mut G) -> Self {
        Hsl {
            h: g.gen_range(0.0, 360.0),
            s: g.gen_range(0.0, 1.0),
            l: g.gen_range(0.0, 1.0),
        }
    }
}

// Properties that we can have `quickcheck` assert for us.

pub fn rgb_to_hsl_doesnt_panic(rgb: Rgb) {
    let _ = rgb.to_hsl();
}

pub fn rgb_to_hsl_to_rgb_is_identity(rgb: Rgb) {
    assert_eq!(rgb, rgb.to_hsl().to_rgb());
}

#[cfg(test)]
mod tests {
    quickcheck::quickcheck! {
        fn rgb_to_hsl_doesnt_panic(rgb: Rgb) -> bool {
            super::rgb_to_hsl_doesnt_panic(rgb);
            true
        }
    }

    quickcheck::quickcheck! {
        fn rgb_to_hsl_to_rgb_is_identity(rgb: Rgb) -> bool {
            super::rgb_to_hsl_to_rgb_is_identity(rgb);
            true
        }
    }
}
```

Finally, we can *reuse* our existing structure-aware test case generators (the
`Arbitrary` impls) with libFuzzer of AFL inputs with `BufRng`. Thus we can
leverage coverage-guided fuzzing &mdash; where the fuzzer is observing code
coverage while tests are running, and trying to maximize the paths the inputs
cover &mdash; with our existing structure-aware generators.

The following snippet is with [`cargo fuzz` and
libFuzzer](https://rust-fuzz.github.io/book/cargo-fuzz.html), but the concepts
would apply equally well to AFL, for example.

```ignore
// my-rgb-to-hsl-crate/fuzz/fuzz_targets/rgb.rs

#![no_main]

#[macro_use]
extern crate libfuzzer_sys;

use bufrng::BufRng;
use my_rgb_to_hsl_crate::{rgb_to_hsl_doesnt_panic, rgb_to_hsl_to_rgb_is_identity, Rgb};
use quickcheck::Arbitrary;

fuzz_target!(|data: &[u8]| {
    // Create a `BufRng` from the raw data given to us by the fuzzer.
    let mut rng = BufRng::new(data);

    // Generate an `Rgb` instance with it.
    let rgb = Rgb::arbitrary(&mut rng);

    // Assert our properties!
    rgb_to_hsl_doesnt_panic(rgb);
    rgb_to_hsl_to_rgb_is_identity(rgb);
});
```

 */

use rand_core::{Error, RngCore};
use std::iter;
use std::slice;

/// A "random" number generator that yields values from a given buffer (and then
/// zeros after the buffer is exhausted).
///
/// See the module documentation for details.
pub struct BufRng<'a> {
    iter: iter::Chain<slice::Iter<'a, u8>, iter::Repeat<&'a u8>>,
}

impl BufRng<'_> {
    /// Construct a new `BufRng` that yields from the given `data` buffer.
    ///
    /// # Example
    ///
    /// ```
    /// use bufrng::BufRng;
    /// use rand::prelude::*;
    ///
    /// // Create a new `BufRng` by giving it a buffer.
    /// let mut rng = BufRng::new(&[1, 2, 3, 4]);
    ///
    /// // It will generate "random" values, which are copied from the buffer.
    /// assert_eq!(rng.gen::<u32>(), (1 << 24) | (2 << 16) | (3 << 8) | 4);
    ///
    /// // Once the buffer is exhausted, the RNG will keep yielding `0`.
    /// assert_eq!(rng.gen::<u32>(), 0);
    /// assert_eq!(rng.gen::<u32>(), 0);
    /// assert_eq!(rng.gen::<u32>(), 0);
    /// ```
    pub fn new(data: &[u8]) -> BufRng {
        BufRng {
            iter: data.iter().chain(iter::repeat(&0)),
        }
    }
}

// NB: all `RngCore` get a blanket `Rng` implementation.
impl RngCore for BufRng<'_> {
    fn next_u32(&mut self) -> u32 {
        let a = *self.iter.next().unwrap() as u32;
        let b = *self.iter.next().unwrap() as u32;
        let c = *self.iter.next().unwrap() as u32;
        let d = *self.iter.next().unwrap() as u32;
        (a << 24) | (b << 16) | (c << 8) | d
    }

    fn next_u64(&mut self) -> u64 {
        rand_core::impls::next_u64_via_u32(self)
    }

    fn fill_bytes(&mut self, dest: &mut [u8]) {
        rand_core::impls::fill_bytes_via_next(self, dest)
    }

    fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
        Ok(self.fill_bytes(dest))
    }
}