* fuzz: improve the API of the `wasm-spec-interpreter` crate This change addresses key parts of #4852 by improving the bindings to the OCaml spec interpreter. The new API allows users to `instantiate` a module, `interpret` named functions on that instance, and `export` globals and memories from that instance. This currently leaves the existing implementation ("instantiate and interpret the first function in a module") present under a new name: `interpret_legacy`. * fuzz: adapt the differential spec engine to the new API This removes the legacy uses in the differential spec engine, replacing them with the new `instantiate`-`interpret`-`export` API from the `wasm-spec-interpreter` crate. * fix: make instance access thread-safe This changes the OCaml-side definition of the instance so that each instance carries round a reference to a "global store" that's specific to that instantiation. Because everything is updated by reference there should be no visible behavioural change on the Rust side, apart from everything suddenly being thread-safe (modulo the fact that access to the OCaml runtime still needs to be locked). This fix will need to be generalised slightly in future if we want to allow multiple modules to be instantiated in the same store. Co-authored-by: conrad-watt <cnrdwtt@gmail.com> Co-authored-by: Alex Crichton <alex@alexcrichton.com>
cargo fuzz Targets for Wasmtime
This crate defines various libFuzzer
fuzzing targets for Wasmtime, which can be run via cargo fuzz.
These fuzz targets just glue together pre-defined test case generators with
oracles and pass libFuzzer-provided inputs to them. The test case generators and
oracles themselves are independent from the fuzzing engine that is driving the
fuzzing process and are defined in wasmtime/crates/fuzzing.
Example
To start fuzzing run the following command, where $MY_FUZZ_TARGET is one of
the available fuzz targets:
cargo fuzz run $MY_FUZZ_TARGET
Available Fuzz Targets
At the time of writing, we have the following fuzz targets:
api_calls: stress the Wasmtime API by executing sequences of API calls; only the subset of the API is currently supported.compile: Attempt to compile libFuzzer's raw input bytes with Wasmtime.compile-maybe-invalid: Attempt to compile a wasm-smith-generated Wasm module with code sequences that may be invalid.cranelift-fuzzgen: Generate a Cranelift function and check that it returns the same results when compiled to the host and when using the Cranelift interpreter; only a subset of Cranelift IR is currently supported.cranelift-icache: Generate a Cranelift function A, applies a small mutation to its source, yielding a function A', and checks that A compiled + incremental compilation generates the same machine code as if A' was compiled from scratch.differential: Generate a Wasm module, evaluate each exported function with random inputs, and check that Wasmtime returns the same results as a choice of another engine: the Wasm spec interpreter (see thewasm-spec-interpretercrate), thewasmiinterpreter, V8 (through thev8crate), or Wasmtime itself run with a different configuration.instantiate: Generate a Wasm module and Wasmtime configuration and attempt to compile and instantiate with them.instantiate-many: Generate many Wasm modules and attempt to compile and instantiate them concurrently.spectests: Pick a random spec test and run it with a generated configuration.table_ops: Generate a sequence ofexternreftable operations and run them in a GC environment.
The canonical list of fuzz targets is the .rs files in the fuzz_targets
directory:
ls wasmtime/fuzz/fuzz_targets/
Corpora
While you can start from scratch, libFuzzer will work better if it is given a corpus of seed inputs to kick start the fuzzing process. We maintain a corpus for each of these fuzz targets in a dedicated repo on github.
You can use our corpora by cloning it and placing it at wasmtime/fuzz/corpus:
git clone \
https://github.com/bytecodealliance/wasmtime-libfuzzer-corpus.git \
wasmtime/fuzz/corpus
Reproducing a Fuzz Bug
When investigating a fuzz bug (especially one found by OSS-Fuzz), use the following steps to reproduce it locally:
- Download the test case (either the "Minimized Testcase" or "Unminimized Testcase" from OSS-Fuzz will do).
- Run the test case in the correct fuzz target:
If all goes well, the bug should reproduce and libFuzzer will dump the failure stack trace to stdout
cargo +nightly fuzz run <target> <test case> - For more debugging information, run the command above with
RUST_LOG=debugto print the configuration and WebAssembly input used by the test case (see uses oflog_wasmin thewasmtime-fuzzingcrate).