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
//! # Byte Mutator
//!
//! `byte-mutator` is a crate for defining a set of rules by which to mutate byte arrays. It
//! contains two main primitives: `Stage`, and `Mutator`. A `Stage` defines how many iterations
//! to run via the `Iterations` enum, and a `Mutator` defines which `MutatorType` to perform across
//! which range of bytes.
//!
//!`byte-mutator` internally uses an `UndoBuffer`, which is a data structure that exposes mutable
//! `&[u8]` slices, and can undo changes in order to reset and perform another mutation from the
//! clean starting state provided at initialization. This is important to avoid utterly mangling
//! the input; we want to identify small novel changes that produce a different output from the
//! target program, and then reuse that new state to perform further mutations.
//!
//! ```
//! ```
use serde_derive::Deserialize;

pub use crate::fuzz_config::FuzzConfig;
pub use crate::mutators::{Mutation, MutationType};
pub use crate::undo_buffer::UndoBuffer;

pub mod fuzz_config;
pub mod mutators;
pub mod undo_buffer;

/// Used to limit the number of iterations in a `Stage`.
#[derive(Clone, Debug, Deserialize)]
pub enum Iterations {
    /// One iteration per bit in slice
    Bits,
    /// One iteration per byte in slice
    Bytes,
    /// Goes forever
    Unlimited,
    /// Fixed number of iterations
    Limited(usize),
}

/// Used to define groups of mutations, and how many mutations should be performed.
#[derive(Clone, Debug, Deserialize)]
pub struct Stage {
    /// Current number of iterations.
    /// This can start at > 0 if you want to reproduce something from an earlier run.
    pub count: usize,
    /// Max number of iterations
    pub iterations: Iterations,
    /// Group of mutations, all of which are performed every time.
    pub mutations: Vec<Mutation>,
}

impl Stage {
    /// Creates a new `Stage`
    pub fn new(count: usize, mutations: Vec<Mutation>, iterations: Iterations) -> Self {
        Self {
            count,
            mutations,
            iterations,
        }
    }

    /// Returns whether the stage is complete
    pub fn is_done(&self, num_bytes: usize) -> bool {
        match self.iterations {
            Iterations::Bits => self.count >= num_bytes * 8,
            Iterations::Bytes => self.count >= num_bytes,
            Iterations::Limited(n) => self.count >= n,
            Iterations::Unlimited => false,
        }
    }

    /// Advances the internal state of the `Stage`
    pub fn next(&mut self) {
        self.count += 1;
    }

    /// Add a mutation
    pub fn add_mutation(&mut self, mutation: Mutation) {
        self.mutations.push(mutation);
    }
}

impl Default for Stage {
    /// Default `Stage` with no mutations and unlimited iterations
    fn default() -> Self {
        Stage::new(0, vec![], Iterations::Unlimited)
    }
}

/// A fixed size buffer with a defined set of stages of mutations that will be applied to the buffer
#[derive(Debug, Clone)]
pub struct ByteMutator {
    bytes: UndoBuffer,
    /// Queue of outstanding stages, ordered from first to last. Drains from the front.
    stages: Vec<Stage>,
    /// The in-progress stage.
    cur_stage: usize,
}

impl ByteMutator {
    /// Create a new `ByteMutator` from the provided byte slice. Copies into two internal buffers.
    pub fn new(bytes: &[u8]) -> Self {
        Self {
            bytes: UndoBuffer::new(bytes),
            stages: vec![],
            cur_stage: 0,
        }
    }

    pub fn with_stages(mut self, stages: Vec<Stage>) -> Self {
        self.stages = stages;
        self
    }

    /// Creates a new `ByteMutator` and consumes the `stages` configured in `config`
    pub fn new_from_config(bytes: &[u8], config: FuzzConfig) -> Self {
        Self {
            bytes: UndoBuffer::new(bytes),
            stages: config.stages,
            cur_stage: 0,
        }
    }

    /// Number of outstanding stages
    pub fn remaining_stages(&self) -> usize {
        self.stages.len()
    }

    /// Add a stage
    pub fn add_stage(&mut self, stage: Stage) {
        self.stages.push(stage);
    }

    /// Advance the mutation one step. Resets outstanding changes, advances the stage state,
    /// and mutates using all mutators defined in the stage.
    pub fn next(&mut self) {
        let stage = match self.stages.get_mut(0) {
            None => return, // nothing to do
            Some(s) => s,
        };

        // we reset the last change first so that we're getting small changes not huge ones
        self.bytes.undo();

        for mutation in &mut stage.mutations {
            match mutation.range {
                Some((start, end)) => {
                    mutation.mutate(self.bytes.get_mut_range(start, end), stage.count)
                }
                None => mutation.mutate(self.bytes.get_mut(), stage.count),
            };
        }

        stage.next();

        if stage.is_done(self.bytes.len()) {
            self.stages.drain(..1);
            self.bytes.undo();
        }
    }

    /// Returns an immutable slice of the mutable buffer.
    /// Exposes the current state of the `ByteMutator`.
    pub fn read(&self) -> &[u8] {
        self.bytes.read()
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::mutators::MutationType;

    #[test]
    fn mutator_stage() {
        let mut byte_mutator = ByteMutator::new(b"foo");

        byte_mutator.add_stage(Stage::new(
            0,
            vec![Mutation {
                range: None,
                mutation: MutationType::BitFlipper { width: 1 },
            }],
            Iterations::Limited(10),
        ));

        assert_eq!(byte_mutator.remaining_stages(), 1);

        for _ in 0..10 {
            byte_mutator.next();
        }

        assert_eq!(byte_mutator.remaining_stages(), 0);
    }
}