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 } }