From 0833d467bd55ee7ff427e0484fc299366ad9ab7d Mon Sep 17 00:00:00 2001 From: Danilo Bargen Date: Tue, 6 Jul 2021 14:50:50 +0200 Subject: [PATCH] Add afl fuzz tests (#272) * Add afl fuzz tests * Add reproducer binary for protobuf files Co-authored-by: Lucio Franco --- Cargo.toml | 2 ++ FUZZING.md | 27 +++++++++++++++++++++++++++ afl/.gitignore | 2 ++ afl/proto3/Cargo.toml | 18 ++++++++++++++++++ afl/proto3/README.md | 30 ++++++++++++++++++++++++++++++ afl/proto3/in/empty | 0 afl/proto3/in/testmessage | Bin 0 -> 71 bytes afl/proto3/src/main.rs | 10 ++++++++++ afl/proto3/src/reproduce.rs | 13 +++++++++++++ 9 files changed, 102 insertions(+) create mode 100644 FUZZING.md create mode 100644 afl/.gitignore create mode 100644 afl/proto3/Cargo.toml create mode 100644 afl/proto3/README.md create mode 100644 afl/proto3/in/empty create mode 100644 afl/proto3/in/testmessage create mode 100644 afl/proto3/src/main.rs create mode 100644 afl/proto3/src/reproduce.rs diff --git a/Cargo.toml b/Cargo.toml index 541dc1d78..84ce19d22 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,6 +29,8 @@ exclude = [ # The fuzz crate can't be compiled or tested without the 'cargo fuzz' command, # so exclude it from normal builds. "fuzz", + # Same counts for the afl fuzz targets + "afl", ] [lib] diff --git a/FUZZING.md b/FUZZING.md new file mode 100644 index 000000000..d47268d69 --- /dev/null +++ b/FUZZING.md @@ -0,0 +1,27 @@ +# Fuzzing + +Prost ships a few fuzz tests, using both libfuzzer and aflfuzz. + + +## afl + +To run the afl fuzz tests, first install cargo-afl: + + cargo install -f afl + +Then build a fuzz target and run afl on it: + + cd afl// + cargo afl build --bin fuzz-target + cargo afl fuzz -i in -o out target/debug/fuzz-target + +To reproduce a crash: + + cd afl// + cargo build --bin reproduce + cargo run --bin reproduce -- out/crashes/ + + +## libfuzzer + +TODO diff --git a/afl/.gitignore b/afl/.gitignore new file mode 100644 index 000000000..1776e1323 --- /dev/null +++ b/afl/.gitignore @@ -0,0 +1,2 @@ +out/ +core.* diff --git a/afl/proto3/Cargo.toml b/afl/proto3/Cargo.toml new file mode 100644 index 000000000..d1e00d5df --- /dev/null +++ b/afl/proto3/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "fuzz-target-proto3" +version = "0.1.0" +authors = ["Prost developers"] +edition = "2018" + +[[bin]] +name = "fuzz-target" +path = "src/main.rs" + +[[bin]] +name = "reproduce" +path = "src/reproduce.rs" + +[dependencies] +afl = "0.4" +protobuf = { path = "../../protobuf/" } +tests = { path = "../../tests/" } diff --git a/afl/proto3/README.md b/afl/proto3/README.md new file mode 100644 index 000000000..064bfdb1a --- /dev/null +++ b/afl/proto3/README.md @@ -0,0 +1,30 @@ +# proto3 fuzz tests + +## Test corpus + +The test message `testmessage` was created like this: + +```rust +use prost::Message; +use protobuf::test_messages::proto3::TestAllTypesProto3; + +fn main() { + let msg = TestAllTypesProto3 { + optional_int32: 42, + optional_fixed64: 9983748923, + optional_bool: true, + recursive_message: Some( + Box::new(TestAllTypesProto3 { + repeated_int32: vec![1, 2, 99, 50, -5], + ..Default::default() + }) + ), + repeated_sfixed32: vec![1, -1, 1, -1], + repeated_float: vec![-1.0, 10.10, 1.337, std::f32::NAN], + ..Default::default() + }; + let mut buf = vec![]; + msg.encode(&mut buf).unwrap(); + std::fs::write("proto3-default.bin", buf).unwrap(); +} +``` diff --git a/afl/proto3/in/empty b/afl/proto3/in/empty new file mode 100644 index 000000000..e69de29bb diff --git a/afl/proto3/in/testmessage b/afl/proto3/in/testmessage new file mode 100644 index 0000000000000000000000000000000000000000..a95f310621fc872862fefceb4aa167b24418fe6a GIT binary patch literal 71 zcmdvXsi&5|wBOfDEveEDVP{6p0Nq`Y33F5-&Q%nL33=R8d%~W)} MsI=Oif#E(data).unwrap_error(); + }); +} diff --git a/afl/proto3/src/reproduce.rs b/afl/proto3/src/reproduce.rs new file mode 100644 index 000000000..ab0c0f9c5 --- /dev/null +++ b/afl/proto3/src/reproduce.rs @@ -0,0 +1,13 @@ +use protobuf::test_messages::proto3::TestAllTypesProto3; +use tests::roundtrip; + +fn main() { + let args: Vec = std::env::args().collect(); + if args.len() != 2 { + println!("Usage: {} ", args[0]); + std::process::exit(1); + } + + let data = std::fs::read(&args[1]).expect(&format!("Could not open file {}", args[1])); + let _ = roundtrip::(&data).unwrap_error(); +}