Create A Harness Closure

Before we can write our closure, we'll need to add a few use declarations from libafl. Add these at the top of your main.rs file:

#![allow(unused)]
fn main() {
use libafl::prelude::{BytesInput, AsSlice, HasTargetBytes, ExitKind};
}

BytesInput is a type that describes an input from the fuzzer that is just a sequence of bytes. It's the standard input type, although it is possible to define custom input types as we'll see in later exercises. BytesInput under the hood is just a Vec<u8> with some sugar around it to make it easy to use in the context of a possibly distributed and multi-threaded fuzzer.

HasTargetBytes is a trait (which we will dive deep into later, but for now you can think of as similar to an interface in Java or a concept in C++) that is implemented by BytesInput and returns the contents of the BytesInput as an OwnedSlice<u8>.

An OwnedSlice<T> wraps a slice (in this case a &[u8]) so that it is serializable (we'll discuss serializability later) and can be sent between threads, processes, and machines over the network easily. LibAFL has several Owned types used for this purpose: OwnedRef<T>, OwnedRefMut<T>, OwnedPtr<T>, OwnedMutPtr<T>, OwnedSlice<T> and OwnedMutSlice<T>. Each wraps the underlying type, whether it is a &T/&mut T, *const T/*mut T, or &[T]/&mut [T].

AsSlice is another trait implemented by OwnedSlice and allows the OwnedSlice<u8> to be converted to &[u8], which we'll then input to our decode function.

With all that knowledge, our harness closure is pretty simple. We take our BytesInput, convert it to an OwnedSlice<u8>, convert that to a &[u8], and call our target function.

fn main() {
    let args = Args::parse();

    let mut harness = |input: &BytesInput| {
        let target = input.target_bytes();
        let buf = target.as_slice();
        println!("Fuzzing with {:?} ({})", buf, buf.len());
        unsafe { decode(buf) };
        ExitKind::Ok
    }
}