A Move source code level fuzzer.
Make sure you have all the necessary dependencies.
To start a basic fuzzing session, run
cargo fuzz run <fuzz_target>
To run more advanced session that runs 10 workers in parallel, use the fuzz.sh
script:
./scripts/fuzz.sh <fuzz_target> [total_hour] [max_input_len] [timeout]
# If `max_input_len` is 0, initial random corpus will be generated.
# For example
./scripts/fuzz.sh transactional 24 4 3
# This will run the `transactional` target for 24 hours with randomly created
# seeds whose size doesn't exceed 4KB.
# For each input, it will timeout after 3 seconds.
# If a fuzz target starts with `afl++`, the script will spawn nodes in a tmux session:
./scripts/fuzz.sh afl-transactional 24 4
# This will create a tmux session `afl_fuzzing` where each node occupies a window.
The script will keep a copy of log under logs
.
Note that the script will automatically spawn tmux sessions for running AFL++
fuzzing sessions so be careful using AFL inside a tmux session.
All fuzz targets live in fuzz/fuzz_targets
:
compile_only
: compiles the generated Move programs using both compiler V1 and V2 and compare if they both success or failtransactional
: run the generated Move programs as transactional tests so that we can cover compiler V1, V2, and the VMafl-transactional
: the same as transactional but uses AFL++ instead of libfuzzer
For libFuzzer, crashing inputs are stored in fuzz/artifacts/<fuzz_target>
.
For AFL++, they are stored in fuzz/afl/<fuzz_target>_out/fuzzer#/crashes
.
raw2move
converts bytes from STDIN to a Move program the same as how the fuzzer
uses raw input. The resulting Move code will be printed to STDOUT.
cargo run --bin raw2move < fuzz/artifacts/<fuzz_target>/<input_file>
generator
can statically generate a number of Move files/packages with a fixed seed.
This could be helpful to debug the fuzzer or to use the generated files for other purposes.
The generator can be used by cargo run --bin generator -- <Options>
and available options are:
Options:
-o, --output-dir <OUTPUT_DIR> The output directory to store the generated Move files
-s, --seed <SEED> An optional number as seed, the default should be 0 [default: 0]
-n, --num-files <NUM_FILES> An optional number as the number of files to generate, the default should be 100 [default: 100]
-p, --package A boolean flag to create a package, default to false
run_transactional
takes input the path to a Move file and runs it as transactional test.
cargo run --bin run_transactional path/to/file.move
check_artifact
essentially is the combination of raw2move
and run_transactional
:
it reads a file that contains raw bytes, converts it to Move, compiles and runs it as
transactional test.
cargo run --bin check_artifact -- -f path/to/raw/input
After running a fuzzing session, the coverage of all stored corpus can be generated by:
./scripts/coverage.sh <fuzz_target> [base_dir]
If the fuzzing session was run on the local machine, you can ignore base_dir
.
If you want to generate the coverage from a different corpus (e.g. generated from another machine),
use the base_dir
to specify the directory that contains fuzz/
where corpus
is stored for libFuzzer,
or afl
is stored for AFL++.
This will create an HTML report at [base_dir/]coverage/<fuzz_target>/index.html
.
For libFuzzer results, you can use the scipts/coverage_graph.py
to draw a coverage over time graph:
python scripts/coverage_graph.py path/to/log
For AFL++ results, you can use
cargo afl plot fuzz/afl/<fuzz_target>_out/fuzzer0 <ouput_dir>
to plot several key statistics.
They can be viewed at <output_dir>/index.html
.
The script ./scripts/check_output.sh
is a helper for checking the generated programs.
By default it generates 10 Move packages stored in output/
, compiles with both compilers, run transactional tests,
and reports any error encountered.
Use ./scripts/check_output.sh N
to generate N
packages instead.
To execute the generated Move programs as transactional tests, use the script:
./scripts/transactional-test.sh N
This script will generate N
programs under third_party/move/move-compiler-v2/transactional-tests/tests/move-smith
.
It will than apply a patch to the test harness to only run with the newly generated files.
cargo-fuzz provides many handy commands for running fuzzing. Install with:
cargo install cargo-fuzz
To run AFL++ targets, you need to install cargo-afl:
cargo install cargo-afl
To plot AFL++ statistics, you might need to install gnuplot
:
brew install gnuplot
The nightly rust toolchain is required for instrumenting the code. Install with:
rustup install nightly
To overwrite the top-level rust-toolchain.toml
, use:
rustup override set nightly
To generate human-readable coverage reports, we need llvm
coverage tools.
They can be installed with:
cargo install cargo-binutils
rustup component add --toolchain nightly llvm-tools-preview
.
├── Cargo.toml
├── README.md
├── fuzz
│ ├── Cargo.toml
│ ├── artifacts # The inputs that trigger crashes (created after a fuzzing session starts)
│ ├── corpus # The corpus of inputs for all fuzz targets (created after a fuzzing session starts)
│ ├── coverage # Stores the aggregated raw coverage files (created after collecting coverage)
│ └── fuzz_targets
│ ├── afl_transactional.rs # Same as `transactional` but uses AFL++
│ ├── compile_only.rs # Generates and compiles a module with both compiler V1 and V2
│ └── transactional.rs # Run the generated Move programs as transactional tests to cover V1, V2, and the VM
├── scripts
│ ├── check_artifacts.sh # Parse, compile, and run a raw input file
│ ├── check_output.sh # Generate Move programs/packages and try to compile them
│ ├── coverage.sh # Collect coverage and generate human-readable reports.
│ ├── coverage_graph.py # Parses libfuzzer output and draw a coverage-over-time graph.
│ ├── fuzz.sh # Helper script for running libfuzzer and AFL++
│ ├── take_snapshot.sh # Take a snapshot of a fuzzing session run on a remote machine
│ ├── transactional-test.sh # Generate Move programs and execute them as transactional tests.
│ └── transactional-tests.patch # Disables all other tests and only run MoveSmith generated ones.
├── src
│ ├── ast.rs # The AST for the Move language by the fuzzer
│ ├── cli
│ │ ├── check_artifact.rs # ra2move + run_transactional
│ │ ├── flame.rs # Helper CLI for profiling the fuzzer
│ │ ├── generator.rs # The static generator for debugging
│ │ ├── raw2move.rs # Converts raw bytes from stdin to a Move program
│ │ └── run_transactional.rs # Run a Move file as transactional test
│ ├── codegen.rs # Converts the AST to textual Move code
│ ├── config.rs # Fuzzer configurations
│ ├── env.rs # Keep track of information about the already generated partial program
│ ├── lib.rs
│ ├── move_smith.rs # The core generation logic
│ ├── names.rs # Manages identifiers, scoping, liveness
│ ├── types.rs # Manages type checking, abilities
│ └── utils.rs # Connects to compilers & VM
└── tests
└── integration_test.rs # Various sanity checks