Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fuzzing Tooling: cmin and precise stack trace for PartialVMErrors #15739

Merged
merged 4 commits into from
Jan 19, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions testsuite/fuzzer/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ The script includes several functions to manage and execute fuzz tests:
```bash
./fuzz.sh build-oss-fuzz <target_dir>
```
- `cmin`: Distillate corpora
```bash
./fuzz.sh cmin <fuzz_target> [corpora_directory]
```
- `coverage`: Generates coverage report in HTML format
```bash
./fuzz.sh coverage <fuzz_target>
Expand Down Expand Up @@ -124,6 +128,13 @@ The CSV file is structured as follows:
- Column 2: Module address
- Column 3: Base64-encoded bytecode of the module

## Debug Crashes
Flamegraph and GDB are integrated into fuzz.sh for advanced metrics and debugging. A more rudimentary option is also available: since we have symbolized binaries, we can directly use the stack trace produced by the fuzzer. However, for INVARIANT_VIOLATIONS, the stack trace is incorrect. To obtain the correct stack trace, you can use the following command:
```bash
DEBUG_VM_STATUS=<status_reported_by_the_fuzzer> ./fuzz.sh run <fuzzer_target> <test_case>
```
This command is selective, so only the specified, comma-separated statuses will trigger the panic in PartialVMError.

## References
- [Rust Fuzz Book](https://rust-fuzz.github.io/book/)
- [Google OSS-Fuzz](https://google.github.io/oss-fuzz/)
Expand Down
19 changes: 18 additions & 1 deletion testsuite/fuzzer/fuzz.sh
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ function usage() {
"build-oss-fuzz")
echo "Usage: $0 build-oss-fuzz <target_dir>"
;;
"cmin")
echo "Usage: $0 cmin <fuzz_target> [corpus_dir]"
;;
"coverage")
echo "Usage: $0 coverage <fuzz_target>"
;;
Expand Down Expand Up @@ -80,6 +83,7 @@ function usage() {
echo " block-builder runs rust tool to hel build fuzzers"
echo " build builds fuzz targets"
echo " build-oss-fuzz builds fuzz targets for oss-fuzz"
echo " cmin minimizes a corpus for a target"
echo " coverage generates coverage for a fuzz target"
echo " clean-coverage clean coverage for a fuzz target"
echo " debug debugs a fuzz target with a testcase"
Expand Down Expand Up @@ -166,6 +170,15 @@ function build-oss-fuzz() {
done
}

function cmin() {
if [ -z "$1" ]; then
usage cmin
fi
fuzz_target=$1
corpus_dir=${2:-./fuzz/corpus/$fuzz_target}
cargo_fuzz cmin $fuzz_target $corpus_dir
}

function install-coverage-tools() {
cargo +$NIGHTLY_VERSION install cargo-binutils
cargo +$NIGHTLY_VERSION install rustfilt
Expand Down Expand Up @@ -271,7 +284,7 @@ function run() {
fi
fi
info "Running $fuzz_target"
cargo_fuzz run --sanitizer none -O $fuzz_target $testcase -- -fork=10
cargo_fuzz run --sanitizer address -O $fuzz_target $testcase -- -fork=15 #-ignore_crashes=1
}

function test() {
Expand Down Expand Up @@ -340,6 +353,10 @@ case "$1" in
shift
build-oss-fuzz "$@"
;;
"cmin")
shift
cmin "$@"
;;
"coverage")
shift
coverage "$@"
Expand Down
21 changes: 21 additions & 0 deletions third_party/move/move-binary-format/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,23 @@ pub type VMResult<T> = ::std::result::Result<T, VMError>;
pub type BinaryLoaderResult<T> = ::std::result::Result<T, PartialVMError>;
pub type PartialVMResult<T> = ::std::result::Result<T, PartialVMError>;

/// This macro is used to panic while debugging fuzzing crashes obtaining the right stack trace.
/// e.g. DEBUG_VM_STATUS=ABORTED,UNKNOWN_INVARIANT_VIOLATION_ERROR ./fuzz.sh run move_aptosvm_publish_and_run <testcase>
/// third_party/move/move-core/types/src/vm_status.rs:506 for the list of status codes.
#[cfg(feature = "fuzzing")]
macro_rules! fuzzing_maybe_panic {
($major_status:expr, $message:expr) => {{
if let Ok(debug_statuses) = std::env::var("DEBUG_VM_STATUS") {
if debug_statuses
.split(',')
.any(|s| s.trim() == format!("{:?}", $major_status))
{
panic!("PartialVMError: {:?} {:?}", $major_status, $message);
}
}
}};
}

#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub enum Location {
Undefined,
Expand Down Expand Up @@ -438,6 +455,10 @@ impl PartialVMError {
} else {
None
};

#[cfg(feature = "fuzzing")]
fuzzing_maybe_panic!(major_status, message);

Self(Box::new(PartialVMError_ {
major_status,
sub_status: None,
Expand Down
Loading