From c75337e6581ace49459f79bc4e259b10ec3548eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Fri, 17 Feb 2023 17:01:31 +0100 Subject: [PATCH] Add basic fuzzing --- fuzz/.gitignore | 4 ++ fuzz/Cargo.toml | 31 +++++++++++ fuzz/fuzz_targets/fuzz_target_1.rs | 86 ++++++++++++++++++++++++++++++ 3 files changed, 121 insertions(+) create mode 100644 fuzz/.gitignore create mode 100644 fuzz/Cargo.toml create mode 100644 fuzz/fuzz_targets/fuzz_target_1.rs diff --git a/fuzz/.gitignore b/fuzz/.gitignore new file mode 100644 index 0000000..1a45eee --- /dev/null +++ b/fuzz/.gitignore @@ -0,0 +1,4 @@ +target +corpus +artifacts +coverage diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml new file mode 100644 index 0000000..914c8f9 --- /dev/null +++ b/fuzz/Cargo.toml @@ -0,0 +1,31 @@ +[package] +name = "cbor-smol-fuzz" +version = "0.0.0" +publish = false +edition = "2018" + +[package.metadata] +cargo-fuzz = true + +[dependencies] +libfuzzer-sys = "0.4" +arbitrary = { version = "1.2.3", features = ["derive"] } +serde = { version = "1.0.152", features = ["derive"] } +serde_bytes = "0.11.9" +serde_cbor = "0.11.2" + +[dependencies.cbor-smol] +path = ".." + +# Prevent this from interfering with workspaces +[workspace] +members = ["."] + +[profile.release] +debug = 1 + +[[bin]] +name = "fuzz_target_1" +path = "fuzz_targets/fuzz_target_1.rs" +test = false +doc = false diff --git a/fuzz/fuzz_targets/fuzz_target_1.rs b/fuzz/fuzz_targets/fuzz_target_1.rs new file mode 100644 index 0000000..8f61ffe --- /dev/null +++ b/fuzz/fuzz_targets/fuzz_target_1.rs @@ -0,0 +1,86 @@ +#![no_main] + +use arbitrary::{Arbitrary, Unstructured}; +use libfuzzer_sys::fuzz_target; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, PartialEq, Arbitrary, Serialize, Deserialize)] +enum AllEnums { + I8(i8), + U8(u8), + I16(i16), + U16(u16), + I32(i32), + U32(u32), + // Not implemented + // I64(i64), + U64(u64), + Struct(Struct), + Array([Struct; 4]), + Option(Option), + Vec(Vec), + Bytes(#[serde(with = "serde_bytes")] Vec), + String(String), + Tuple((Struct, Struct)), + TupleVariant(Struct, Struct), + TupleVariantBytes(Struct, Struct, #[serde(with = "serde_bytes")] Vec), + StructVariant { + x: Struct, + y: Struct, + }, + StructVariantBytes { + x: Struct, + y: Struct, + #[serde(with = "serde_bytes")] + z: Vec, + }, +} + +#[derive(Debug, PartialEq, Arbitrary, Serialize, Deserialize)] +struct Struct { + a: Box, + b: Box, +} + +/// Workaround https://github.com/rust-fuzz/arbitrary/issues/144 +#[derive(Debug)] +struct Input<'i>(AllEnums, &'i [u8]); + +impl<'i> Arbitrary<'i> for Input<'i> { + fn arbitrary(u: &mut Unstructured<'i>) -> Result { + Ok(Self(AllEnums::arbitrary(u)?, Arbitrary::arbitrary(u)?)) + } + + fn arbitrary_take_rest(mut u: Unstructured<'i>) -> Result { + Ok(Self( + AllEnums::arbitrary(&mut u)?, + Arbitrary::arbitrary_take_rest(u)?, + )) + } + fn size_hint(_depth: usize) -> (usize, Option) { + (0, None) + } +} + +fuzz_target!(|data: Input<'_>| { + let bytes = data.1; + let data = data.0; + let _res: Option = cbor_smol::cbor_deserialize(&bytes).ok(); + let mut buffer = vec![0; 1024 * 20]; + let res = cbor_smol::cbor_serialize(&data, &mut buffer).unwrap(); + cbor_smol::cbor_deserialize(&res) + .map(|b: AllEnums| { + assert_eq!(data, b); + }) + .map_err(|err| { + let v: Result = serde_cbor::from_slice(&res); + panic!( + "Failed to deserialize: {:?}\n\ + input: {:#?}\n\ + data: {:02x?}\n\ + serde_cbor gives: {:#?}\n", + err, data, res, v + ); + }) + .ok(); +});