bufrngBufRng is a "random" number generator that simply yields pre-determined values
from a buffer, and yields 0s once the buffer is exhausted.
⚠⚠⚠
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!
⚠⚠⚠
BufRng is useful for reinterpreting raw input bytes from
libFuzzer or
AFL as an RNG that is used with
structure-aware test case generators (e.g.
quickcheck::Arbitrary). This
combines the power of coverage-guided fuzzing with structure-aware fuzzing.
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.
```rust /// A color represented with RGB.
pub struct Rgb { pub r: u8, pub g: u8, pub b: u8, }
impl Rgb { pub fn to_hsl(&self) -> Hsl { // ... } }
/// A color represented with HSL.
pub struct Hsl { pub h: f64, pub s: f64, pub l: f64, }
impl Hsl { pub fn to_rgb(&self) -> Rgb { // ... } }
// 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
impl Arbitrary for Hsl {
fn arbitrary
// Properties that we can have quickcheck assert for us.
pub fn rgbtohsldoesntpanic(rgb: Rgb) { let _ = rgb.to_hsl(); }
pub fn rgbtohsltorgbisidentity(rgb: Rgb) { asserteq!(rgb, rgb.tohsl().to_rgb()); }
mod tests { quickcheck::quickcheck! { fn rgbtohsldoesntpanic(rgb: Rgb) -> bool { super::rgbtohsldoesntpanic(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 — where the fuzzer is observing code
coverage while tests are running, and trying to maximize the paths the inputs
cover — with our existing structure-aware generators.
The following snippet is with cargo fuzz and
libFuzzer, but the concepts
would apply equally well to AFL, for example.
```rust // my-rgb-to-hsl-crate/fuzz/fuzz_targets/rgb.rs
extern crate libfuzzer_sys;
use bufrng::BufRng; use myrgbtohslcrate::{rgbtohsldoesntpanic, rgbtohsltorgbisidentity, 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);
}); ```