From a5da9ce42cab1eab93cf80ca744944ae26e6ab58 Mon Sep 17 00:00:00 2001 From: julihoh Date: Sat, 27 Feb 2021 15:05:13 +0100 Subject: custom mutator rust support (#752) * custom mutator rust support * clarify how to view documentation for rust mutators * remove `FuzzResult` hack and clarify lifetimes of CustomMutator::fuzz * rename TErr associated tyep to Error to be more idiomatic * fix warnings * add example for fallible custom mutator * make Fallible Custom Mutator the default and implement it's handle_err method by default * rename CustomMutator::handle_err to handle_error * add example mutator using lain --- custom_mutators/rust/example_lain/src/lib.rs | 60 ++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 custom_mutators/rust/example_lain/src/lib.rs (limited to 'custom_mutators/rust/example_lain/src') diff --git a/custom_mutators/rust/example_lain/src/lib.rs b/custom_mutators/rust/example_lain/src/lib.rs new file mode 100644 index 00000000..3336e861 --- /dev/null +++ b/custom_mutators/rust/example_lain/src/lib.rs @@ -0,0 +1,60 @@ +use custom_mutator::{export_mutator, CustomMutator}; +use lain::{ + mutator::Mutator, + prelude::*, + rand::{rngs::StdRng, SeedableRng}, +}; +use std::os::raw::c_uint; + +#[derive(Debug, Mutatable, NewFuzzed, BinarySerialize)] +struct MyStruct { + field_1: u8, + + #[lain(bits = 3)] + field_2: u8, + + #[lain(bits = 5)] + field_3: u8, + + #[lain(min = 5, max = 10000)] + field_4: u32, + + #[lain(ignore)] + ignored_field: u64, +} + +struct LainMutator { + mutator: Mutator, + buffer: Vec, +} + +impl CustomMutator for LainMutator { + type Error = (); + + fn init(seed: c_uint) -> Result { + Ok(Self { + mutator: Mutator::new(StdRng::seed_from_u64(seed as u64)), + buffer: Vec::new(), + }) + } + + fn fuzz<'b, 's: 'b>( + &'s mut self, + _buffer: &'b mut [u8], + _add_buff: Option<&[u8]>, + max_size: usize, + ) -> Result, ()> { + // we just sample an instance of MyStruct, ignoring the current input + let instance = MyStruct::new_fuzzed(&mut self.mutator, None); + let size = instance.serialized_size(); + if size > max_size { + return Err(()); + } + self.buffer.clear(); + self.buffer.reserve(size); + instance.binary_serialize::<_, BigEndian>(&mut self.buffer); + Ok(Some(self.buffer.as_slice())) + } +} + +export_mutator!(LainMutator); -- cgit 1.4.1 From c219502f0fe654927c3f74f9791f786f0740f344 Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Sat, 27 Feb 2021 15:52:36 +0100 Subject: some rust cleanup --- custom_mutators/rust/Cargo.toml | 3 +- custom_mutators/rust/README.md | 6 ++- custom_mutators/rust/custom_mutator/src/lib.rs | 39 +++++++------- custom_mutators/rust/example/Cargo.toml | 6 ++- .../rust/example/src/example_mutator.rs | 49 ++++++++++++++++++ custom_mutators/rust/example/src/lib.rs | 50 ------------------ custom_mutators/rust/example_lain/Cargo.toml | 4 +- .../rust/example_lain/src/lain_mutator.rs | 59 +++++++++++++++++++++ custom_mutators/rust/example_lain/src/lib.rs | 60 ---------------------- 9 files changed, 139 insertions(+), 137 deletions(-) create mode 100644 custom_mutators/rust/example/src/example_mutator.rs delete mode 100644 custom_mutators/rust/example/src/lib.rs create mode 100644 custom_mutators/rust/example_lain/src/lain_mutator.rs delete mode 100644 custom_mutators/rust/example_lain/src/lib.rs (limited to 'custom_mutators/rust/example_lain/src') diff --git a/custom_mutators/rust/Cargo.toml b/custom_mutators/rust/Cargo.toml index 003bc58a..e36d24b5 100644 --- a/custom_mutators/rust/Cargo.toml +++ b/custom_mutators/rust/Cargo.toml @@ -3,5 +3,6 @@ members = [ "custom_mutator-sys", "custom_mutator", "example", - "example_lain", + # Lain needs a nightly toolchain + # "example_lain", ] \ No newline at end of file diff --git a/custom_mutators/rust/README.md b/custom_mutators/rust/README.md index 119ac790..e2cc38b4 100644 --- a/custom_mutators/rust/README.md +++ b/custom_mutators/rust/README.md @@ -1,9 +1,11 @@ +# Rust Custom Mutators + Bindings to create custom mutators in Rust. These bindings are documented with rustdoc. To view the documentation run ```cargo doc -p custom_mutator --open```. -A minimal example can be found in `example`. +A minimal example can be found in `example`. Build it using `cargo build --example example_mutator`. -An example using [lain](https://github.com/microsoft/lain) can be found in `example_lain`. +An example using [lain](https://github.com/microsoft/lain) for structured fuzzing can be found in `example_lain`. Since lain requires a nightly rust toolchain, you need to set one up before you can play with it. diff --git a/custom_mutators/rust/custom_mutator/src/lib.rs b/custom_mutators/rust/custom_mutator/src/lib.rs index 0fb007ab..b82af250 100644 --- a/custom_mutators/rust/custom_mutator/src/lib.rs +++ b/custom_mutators/rust/custom_mutator/src/lib.rs @@ -23,7 +23,7 @@ //! The state is passed to [`CustomMutator::init`], when the feature is activated. //! //! _This is completely unsafe and uses automatically generated types extracted from the AFL++ source._ -use std::{ffi::CStr, fmt::Debug, os::raw::c_uint}; +use std::{ffi::CStr, fmt::Debug}; #[cfg(feature = "afl_internals")] #[doc(hidden)] @@ -37,7 +37,7 @@ pub trait RawCustomMutator { where Self: Sized; #[cfg(not(feature = "afl_internals"))] - fn init(seed: c_uint) -> Self + fn init(seed: u32) -> Self where Self: Sized; @@ -87,7 +87,7 @@ pub mod wrappers { convert::TryInto, ffi::{c_void, CStr}, mem::ManuallyDrop, - os::raw::{c_char, c_uint}, + os::raw::c_char, panic::catch_unwind, process::abort, ptr::null, @@ -112,13 +112,13 @@ pub mod wrappers { } #[cfg(feature = "afl_internals")] - fn new(afl: &'static afl_state, seed: c_uint) -> Box { + fn new(afl: &'static afl_state, seed: u32) -> Box { Box::new(Self { mutator: M::init(afl, seed), }) } #[cfg(not(feature = "afl_internals"))] - fn new(seed: c_uint) -> Box { + fn new(seed: u32) -> Box { Box::new(Self { mutator: M::init(seed), }) @@ -143,7 +143,7 @@ pub mod wrappers { /// Internal function used in the macro #[cfg(not(feature = "afl_internals"))] - pub fn afl_custom_init_(seed: c_uint) -> *const c_void { + pub fn afl_custom_init_(seed: u32) -> *const c_void { match catch_unwind(|| FFIContext::::new(seed).into_ptr()) { Ok(ret) => ret, Err(err) => panic_handler("afl_custom_init", err), @@ -154,7 +154,7 @@ pub mod wrappers { #[cfg(feature = "afl_internals")] pub fn afl_custom_init_( afl: Option<&'static afl_state>, - seed: c_uint, + seed: u32, ) -> *const c_void { match catch_unwind(|| { let afl = afl.expect("mutator func called with NULL afl"); @@ -328,16 +328,15 @@ pub mod wrappers { /// # #[cfg(feature = "afl_internals")] /// # use custom_mutator::afl_state; /// # use custom_mutator::CustomMutator; -/// # use std::os::raw::c_uint; /// struct MyMutator; /// impl CustomMutator for MyMutator { /// /// ... /// # type Error = (); /// # #[cfg(feature = "afl_internals")] -/// # fn init(_afl_state: &afl_state, _seed: c_uint) -> Result {unimplemented!()} +/// # fn init(_afl_state: &afl_state, _seed: u32) -> Result {unimplemented!()} /// # #[cfg(not(feature = "afl_internals"))] -/// # fn init(_seed: c_uint) -> Result {unimplemented!()} -/// # fn fuzz<'b,'s:'b>(&'s mut self, _buffer: &'b mut [u8], _add_buff: Option<&[u8]>, _max_size: usize) -> Result,()> {unimplemented!()} +/// # fn init(_seed: u32) -> Result {unimplemented!()} +/// # fn fuzz<'b,'s:'b>(&'s mut self, _buffer: &'b mut [u8], _add_buff: Option<&[u8]>, _max_size: usize) -> Result, Self::Error> {unimplemented!()} /// } /// export_mutator!(MyMutator); /// ``` @@ -350,7 +349,7 @@ macro_rules! export_mutator { afl: ::std::option::Option<&'static $crate::afl_state>, seed: ::std::os::raw::c_uint, ) -> *const ::std::os::raw::c_void { - $crate::wrappers::afl_custom_init_::<$mutator_type>(afl, seed) + $crate::wrappers::afl_custom_init_::<$mutator_type>(afl, seed as u32) } #[cfg(not(feature = "afl_internals"))] @@ -359,7 +358,7 @@ macro_rules! export_mutator { _afl: *const ::std::os::raw::c_void, seed: ::std::os::raw::c_uint, ) -> *const ::std::os::raw::c_void { - $crate::wrappers::afl_custom_init_::<$mutator_type>(seed) + $crate::wrappers::afl_custom_init_::<$mutator_type>(seed as u32) } #[no_mangle] @@ -442,8 +441,6 @@ macro_rules! export_mutator { #[cfg(test)] /// this sanity test is supposed to just find out whether an empty mutator being exported by the macro compiles mod sanity_test { - use std::os::raw::c_uint; - #[cfg(feature = "afl_internals")] use super::afl_state; @@ -453,12 +450,12 @@ mod sanity_test { impl RawCustomMutator for ExampleMutator { #[cfg(feature = "afl_internals")] - fn init(_afl: &afl_state, _seed: c_uint) -> Self { + fn init(_afl: &afl_state, _seed: u32) -> Self { unimplemented!() } #[cfg(not(feature = "afl_internals"))] - fn init(_seed: c_uint) -> Self { + fn init(_seed: u32) -> Self { unimplemented!() } @@ -497,12 +494,12 @@ pub trait CustomMutator { } #[cfg(feature = "afl_internals")] - fn init(afl: &'static afl_state, seed: c_uint) -> Result + fn init(afl: &'static afl_state, seed: u32) -> Result where Self: Sized; #[cfg(not(feature = "afl_internals"))] - fn init(seed: c_uint) -> Result + fn init(seed: u32) -> Result where Self: Sized; @@ -544,7 +541,7 @@ where M::Error: Debug, { #[cfg(feature = "afl_internals")] - fn init(afl: &'static afl_state, seed: c_uint) -> Self + fn init(afl: &'static afl_state, seed: u32) -> Self where Self: Sized, { @@ -558,7 +555,7 @@ where } #[cfg(not(feature = "afl_internals"))] - fn init(seed: c_uint) -> Self + fn init(seed: u32) -> Self where Self: Sized, { diff --git a/custom_mutators/rust/example/Cargo.toml b/custom_mutators/rust/example/Cargo.toml index 0c89b200..070d23b1 100644 --- a/custom_mutators/rust/example/Cargo.toml +++ b/custom_mutators/rust/example/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "example" +name = "example_mutator" version = "0.1.0" authors = ["Julius Hohnerlein "] edition = "2018" @@ -9,5 +9,7 @@ edition = "2018" [dependencies] custom_mutator = { path = "../custom_mutator" } -[lib] +[[example]] +name = "example_mutator" +path = "./src/example_mutator.rs" crate-type = ["cdylib"] \ No newline at end of file diff --git a/custom_mutators/rust/example/src/example_mutator.rs b/custom_mutators/rust/example/src/example_mutator.rs new file mode 100644 index 00000000..9b9d4997 --- /dev/null +++ b/custom_mutators/rust/example/src/example_mutator.rs @@ -0,0 +1,49 @@ +#![allow(unused_variables)] + +use custom_mutator::{export_mutator, CustomMutator}; + +struct ExampleMutator; + +impl CustomMutator for ExampleMutator { + type Error = (); + + fn init(seed: u32) -> Result { + Ok(Self) + } + + fn fuzz<'b, 's: 'b>( + &'s mut self, + buffer: &'b mut [u8], + add_buff: Option<&[u8]>, + max_size: usize, + ) -> Result, Self::Error> { + buffer.reverse(); + Ok(Some(buffer)) + } +} + +struct OwnBufferExampleMutator { + own_buffer: Vec, +} + +impl CustomMutator for OwnBufferExampleMutator { + type Error = (); + + fn init(seed: u32) -> Result { + Ok(Self { + own_buffer: Vec::new(), + }) + } + + fn fuzz<'b, 's: 'b>( + &'s mut self, + buffer: &'b mut [u8], + add_buff: Option<&[u8]>, + max_size: usize, + ) -> Result, ()> { + self.own_buffer.reverse(); + Ok(Some(self.own_buffer.as_slice())) + } +} + +export_mutator!(ExampleMutator); diff --git a/custom_mutators/rust/example/src/lib.rs b/custom_mutators/rust/example/src/lib.rs deleted file mode 100644 index 4f9345c0..00000000 --- a/custom_mutators/rust/example/src/lib.rs +++ /dev/null @@ -1,50 +0,0 @@ -#![allow(unused_variables)] - -use custom_mutator::{export_mutator, CustomMutator}; -use std::os::raw::c_uint; - -struct ExampleMutator; - -impl CustomMutator for ExampleMutator { - type Error = (); - - fn init(seed: c_uint) -> Result { - Ok(Self) - } - - fn fuzz<'b, 's: 'b>( - &'s mut self, - buffer: &'b mut [u8], - add_buff: Option<&[u8]>, - max_size: usize, - ) -> Result, ()> { - buffer.reverse(); - Ok(Some(buffer)) - } -} - -struct OwnBufferExampleMutator { - own_buffer: Vec, -} - -impl CustomMutator for OwnBufferExampleMutator { - type Error = (); - - fn init(seed: c_uint) -> Result { - Ok(Self { - own_buffer: Vec::new(), - }) - } - - fn fuzz<'b, 's: 'b>( - &'s mut self, - buffer: &'b mut [u8], - add_buff: Option<&[u8]>, - max_size: usize, - ) -> Result, ()> { - self.own_buffer.reverse(); - Ok(Some(self.own_buffer.as_slice())) - } -} - -export_mutator!(ExampleMutator); diff --git a/custom_mutators/rust/example_lain/Cargo.toml b/custom_mutators/rust/example_lain/Cargo.toml index 1f68c7e0..29d606a4 100644 --- a/custom_mutators/rust/example_lain/Cargo.toml +++ b/custom_mutators/rust/example_lain/Cargo.toml @@ -10,5 +10,7 @@ edition = "2018" custom_mutator = { path = "../custom_mutator" } lain="0.5" -[lib] +[[example]] +name = "example_lain" +path = "./src/lain_mutator.rs" crate-type = ["cdylib"] \ No newline at end of file diff --git a/custom_mutators/rust/example_lain/src/lain_mutator.rs b/custom_mutators/rust/example_lain/src/lain_mutator.rs new file mode 100644 index 00000000..22e5fe73 --- /dev/null +++ b/custom_mutators/rust/example_lain/src/lain_mutator.rs @@ -0,0 +1,59 @@ +use custom_mutator::{export_mutator, CustomMutator}; +use lain::{ + mutator::Mutator, + prelude::*, + rand::{rngs::StdRng, SeedableRng}, +}; + +#[derive(Debug, Mutatable, NewFuzzed, BinarySerialize)] +struct MyStruct { + field_1: u8, + + #[lain(bits = 3)] + field_2: u8, + + #[lain(bits = 5)] + field_3: u8, + + #[lain(min = 5, max = 10000)] + field_4: u32, + + #[lain(ignore)] + ignored_field: u64, +} + +struct LainMutator { + mutator: Mutator, + buffer: Vec, +} + +impl CustomMutator for LainMutator { + type Error = (); + + fn init(seed: u32) -> Result { + Ok(Self { + mutator: Mutator::new(StdRng::seed_from_u64(seed as u64)), + buffer: Vec::new(), + }) + } + + fn fuzz<'b, 's: 'b>( + &'s mut self, + _buffer: &'b mut [u8], + _add_buff: Option<&[u8]>, + max_size: usize, + ) -> Result, ()> { + // we just sample an instance of MyStruct, ignoring the current input + let instance = MyStruct::new_fuzzed(&mut self.mutator, None); + let size = instance.serialized_size(); + if size > max_size { + return Err(()); + } + self.buffer.clear(); + self.buffer.reserve(size); + instance.binary_serialize::<_, BigEndian>(&mut self.buffer); + Ok(Some(self.buffer.as_slice())) + } +} + +export_mutator!(LainMutator); diff --git a/custom_mutators/rust/example_lain/src/lib.rs b/custom_mutators/rust/example_lain/src/lib.rs deleted file mode 100644 index 3336e861..00000000 --- a/custom_mutators/rust/example_lain/src/lib.rs +++ /dev/null @@ -1,60 +0,0 @@ -use custom_mutator::{export_mutator, CustomMutator}; -use lain::{ - mutator::Mutator, - prelude::*, - rand::{rngs::StdRng, SeedableRng}, -}; -use std::os::raw::c_uint; - -#[derive(Debug, Mutatable, NewFuzzed, BinarySerialize)] -struct MyStruct { - field_1: u8, - - #[lain(bits = 3)] - field_2: u8, - - #[lain(bits = 5)] - field_3: u8, - - #[lain(min = 5, max = 10000)] - field_4: u32, - - #[lain(ignore)] - ignored_field: u64, -} - -struct LainMutator { - mutator: Mutator, - buffer: Vec, -} - -impl CustomMutator for LainMutator { - type Error = (); - - fn init(seed: c_uint) -> Result { - Ok(Self { - mutator: Mutator::new(StdRng::seed_from_u64(seed as u64)), - buffer: Vec::new(), - }) - } - - fn fuzz<'b, 's: 'b>( - &'s mut self, - _buffer: &'b mut [u8], - _add_buff: Option<&[u8]>, - max_size: usize, - ) -> Result, ()> { - // we just sample an instance of MyStruct, ignoring the current input - let instance = MyStruct::new_fuzzed(&mut self.mutator, None); - let size = instance.serialized_size(); - if size > max_size { - return Err(()); - } - self.buffer.clear(); - self.buffer.reserve(size); - instance.binary_serialize::<_, BigEndian>(&mut self.buffer); - Ok(Some(self.buffer.as_slice())) - } -} - -export_mutator!(LainMutator); -- cgit 1.4.1