From 6dbfb31d27e02617ee6c69abc58330caa743e2c1 Mon Sep 17 00:00:00 2001 From: Gerardo Di Giacomo Date: Tue, 10 Dec 2024 12:30:38 -0800 Subject: [PATCH] add CompiledModule and CompiledScript deserializer fuzzer (#15494) * add CompiledModule and CompiledScript deserializer fuzzer --- testsuite/fuzzer/fuzz.sh | 20 +++-- testsuite/fuzzer/fuzz/Cargo.toml | 6 ++ .../move/deserialize_script_module.rs | 77 +++++++++++++++++++ 3 files changed, 98 insertions(+), 5 deletions(-) create mode 100644 testsuite/fuzzer/fuzz/fuzz_targets/move/deserialize_script_module.rs diff --git a/testsuite/fuzzer/fuzz.sh b/testsuite/fuzzer/fuzz.sh index c08db0e44faf3..355d1a548d5df 100755 --- a/testsuite/fuzzer/fuzz.sh +++ b/testsuite/fuzzer/fuzz.sh @@ -166,11 +166,22 @@ function build-oss-fuzz() { done } +function install-coverage-tools() { + cargo +$NIGHTLY_VERSION install cargo-binutils + cargo +$NIGHTLY_VERSION install rustfilt +} + function coverage() { if [ -z "$1" ]; then usage coverage fi fuzz_target=$1 + + if ! cargo +$NIGHTLY_VERSION cov -V &> /dev/null; then + install-coverage-tools + fi + + clean-coverage $fuzz_target local corpus_dir="fuzz/corpus/$fuzz_target" local coverage_dir="./fuzz/coverage/$fuzz_target/report" mkdir -p $coverage_dir @@ -184,7 +195,7 @@ function coverage() { fuzz_target_bin=$(find ./target/*/coverage -name $fuzz_target -type f -perm /111) #$(find target/*/coverage -name $fuzz_target -type f) echo "Found fuzz target binary: $fuzz_target_bin" # Generate the coverage report - cargo +nightly cov -- show $fuzz_target_bin \ + cargo +$NIGHTLY_VERSION cov -- show $fuzz_target_bin \ --format=html \ --instr-profile=fuzz/coverage/$fuzz_target/coverage.profdata \ --show-directory-coverage \ @@ -200,12 +211,11 @@ function clean-coverage() { fi local fuzz_target="$1" - local coverage_dir="./fuzz/coverage/$fuzz_target/" - if [ "$fuzz_target" == "all" ]; then - rm -rf coverage + rm -rf ./fuzz/coverage else - rm -rf $target_dir + local coverage_dir="./fuzz/coverage/$fuzz_target/" + rm -rf $coverage_dir fi } diff --git a/testsuite/fuzzer/fuzz/Cargo.toml b/testsuite/fuzzer/fuzz/Cargo.toml index 13a630e928217..7c3c7b4e84997 100644 --- a/testsuite/fuzzer/fuzz/Cargo.toml +++ b/testsuite/fuzzer/fuzz/Cargo.toml @@ -88,3 +88,9 @@ name = "use_case_aware_shuffler" path = "fuzz_targets/use_case_aware_shuffler.rs" test = false doc = false + +[[bin]] +name = "deserialize_script_module" +path = "fuzz_targets/move/deserialize_script_module.rs" +test = false +doc = false diff --git a/testsuite/fuzzer/fuzz/fuzz_targets/move/deserialize_script_module.rs b/testsuite/fuzzer/fuzz/fuzz_targets/move/deserialize_script_module.rs new file mode 100644 index 0000000000000..bbd6d5a063918 --- /dev/null +++ b/testsuite/fuzzer/fuzz/fuzz_targets/move/deserialize_script_module.rs @@ -0,0 +1,77 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +#![no_main] +use arbitrary::Arbitrary; +use libfuzzer_sys::{fuzz_target, Corpus}; +// mod utils; +use move_binary_format::{ + deserializer::DeserializerConfig, file_format::CompiledScript, CompiledModule, +}; + +#[derive(Arbitrary, Debug)] +enum ExecVariant { + Module(CompiledModule), + Script(CompiledScript), + Raw(Vec), +} + +fuzz_target!(|fuzz_data: ExecVariant| -> Corpus { run_case(&fuzz_data) }); + +fn run_case(data: &ExecVariant) -> Corpus { + match data { + ExecVariant::Module(module) => run_case_module(module), + ExecVariant::Script(script) => run_case_script(script), + ExecVariant::Raw(raw_data) => run_case_raw(raw_data), + } +} + +fn run_case_module(module: &CompiledModule) -> Corpus { + let mut module_code = vec![]; + if module.serialize(&mut module_code).is_err() { + return Corpus::Reject; + } + match CompiledModule::deserialize_with_config(&module_code, &DeserializerConfig::default()) { + Ok(mut m) => { + m.version = module.version; + assert_eq!(*module, m); + Corpus::Keep + }, + Err(_) => Corpus::Reject, + } +} + +fn run_case_script(script: &CompiledScript) -> Corpus { + let mut script_code = vec![]; + if script.serialize(&mut script_code).is_err() { + return Corpus::Reject; + } + match CompiledScript::deserialize_with_config(&script_code, &DeserializerConfig::default()) { + Ok(mut s) => { + s.version = script.version; + assert_eq!(*script, s); + Corpus::Keep + }, + Err(_) => Corpus::Reject, + } +} + +fn run_case_raw(raw_data: &Vec) -> Corpus { + if let Ok(m) = CompiledModule::deserialize_with_config(raw_data, &DeserializerConfig::default()) + { + let mut module_code = vec![]; + m.serialize(&mut module_code).unwrap(); + assert_eq!(*raw_data, module_code); + return Corpus::Keep; + } + + if let Ok(s) = CompiledScript::deserialize_with_config(raw_data, &DeserializerConfig::default()) + { + let mut script_code = vec![]; + s.serialize(&mut script_code).unwrap(); + assert_eq!(*raw_data, script_code); + return Corpus::Keep; + } + + Corpus::Reject +}