-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #619 from fitzgen/introduce-wasmtime-fuzzing-crate
Introduce the `wasmtime-fuzzing` crate
- Loading branch information
Showing
11 changed files
with
158 additions
and
92 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -54,6 +54,7 @@ anyhow = "1.0.19" | |
|
||
[workspace] | ||
members = [ | ||
"crates/fuzzing", | ||
"crates/misc/rust", | ||
"crates/misc/py", | ||
] | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
[package] | ||
authors = ["The Wasmtime Project Developers"] | ||
description = "Fuzzing infrastructure for Wasmtime" | ||
edition = "2018" | ||
name = "wasmtime-fuzzing" | ||
publish = false | ||
version = "0.1.0" | ||
|
||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||
|
||
[dependencies] | ||
arbitrary = "0.2.0" | ||
binaryen = "0.8.2" | ||
cranelift-codegen = "0.50.0" | ||
cranelift-native = "0.50.0" | ||
wasmparser = "0.42.1" | ||
wasmtime-jit = { path = "../jit" } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
# Fuzzing Infrastructure for Wasmtime | ||
|
||
This crate provides test case generators and oracles for use with fuzzing. | ||
|
||
These generators and oracles are generally independent of the fuzzing engine | ||
that might be using them and driving the whole fuzzing process (e.g. libFuzzer | ||
or AFL). As such, this crate does *not* contain any actual fuzz targets | ||
itself. Those are generally just a couple lines of glue code that plug raw input | ||
from (for example) `libFuzzer` into a generator, and then run one or more | ||
oracles on the generated test case. | ||
|
||
If you're looking for the actual fuzz target definitions we currently have, they | ||
live in `wasmtime/fuzz/fuzz_targets/*` and are driven by `cargo fuzz` and | ||
`libFuzzer`. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
//! Test case generators. | ||
//! | ||
//! Test case generators take raw, unstructured input from a fuzzer | ||
//! (e.g. libFuzzer) and translate that into a structured test case (e.g. a | ||
//! valid Wasm binary). | ||
//! | ||
//! These are generally implementations of the `Arbitrary` trait, or some | ||
//! wrapper over an external tool, such that the wrapper implements the | ||
//! `Arbitrary` trait for the wrapped external tool. | ||
|
||
use arbitrary::{Arbitrary, Unstructured}; | ||
|
||
/// A Wasm test case generator that is powered by Binaryen's `wasm-opt -ttf`. | ||
pub struct WasmOptTtf { | ||
/// The raw, encoded Wasm bytes. | ||
pub wasm: Vec<u8>, | ||
} | ||
|
||
impl Arbitrary for WasmOptTtf { | ||
fn arbitrary<U>(input: &mut U) -> Result<Self, U::Error> | ||
where | ||
U: Unstructured + ?Sized, | ||
{ | ||
let seed: Vec<u8> = Arbitrary::arbitrary(input)?; | ||
let module = binaryen::tools::translate_to_fuzz_mvp(&seed); | ||
let wasm = module.write(); | ||
Ok(WasmOptTtf { wasm }) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
pub mod generators; | ||
pub mod oracles; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
//! Oracles. | ||
//! | ||
//! Oracles take a test case and determine whether we have a bug. For example, | ||
//! one of the simplest oracles is to take a Wasm binary as our input test case, | ||
//! validate and instantiate it, and (implicitly) check that no assertions | ||
//! failed or segfaults happened. A more complicated oracle might compare the | ||
//! result of executing a Wasm file with and without optimizations enabled, and | ||
//! make sure that the two executions are observably identical. | ||
//! | ||
//! When an oracle finds a bug, it should report it to the fuzzing engine by | ||
//! panicking. | ||
|
||
use cranelift_codegen::settings; | ||
use std::cell::RefCell; | ||
use std::collections::HashMap; | ||
use std::rc::Rc; | ||
use wasmtime_jit::{CompilationStrategy, CompiledModule, Compiler, NullResolver}; | ||
|
||
fn host_isa() -> Box<dyn cranelift_codegen::isa::TargetIsa> { | ||
let flag_builder = settings::builder(); | ||
let isa_builder = cranelift_native::builder().expect("host machine is not a supported target"); | ||
isa_builder.finish(settings::Flags::new(flag_builder)) | ||
} | ||
|
||
/// Instantiate the Wasm buffer, and implicitly fail if we have an unexpected | ||
/// panic or segfault or anything else that can be detected "passively". | ||
/// | ||
/// Performs initial validation, and returns early if the Wasm is invalid. | ||
/// | ||
/// You can control which compiler is used via passing a `CompilationStrategy`. | ||
pub fn instantiate(wasm: &[u8], compilation_strategy: CompilationStrategy) { | ||
if wasmparser::validate(wasm, None).is_err() { | ||
return; | ||
} | ||
|
||
let isa = host_isa(); | ||
let mut compiler = Compiler::new(isa, compilation_strategy); | ||
let mut imports_resolver = NullResolver {}; | ||
|
||
wasmtime_jit::instantiate( | ||
&mut compiler, | ||
wasm, | ||
&mut imports_resolver, | ||
Default::default(), | ||
true, | ||
) | ||
.expect("failed to instantiate valid Wasm!"); | ||
} | ||
|
||
/// Compile the Wasm buffer, and implicitly fail if we have an unexpected | ||
/// panic or segfault or anything else that can be detected "passively". | ||
/// | ||
/// Performs initial validation, and returns early if the Wasm is invalid. | ||
/// | ||
/// You can control which compiler is used via passing a `CompilationStrategy`. | ||
pub fn compile(wasm: &[u8], compilation_strategy: CompilationStrategy) { | ||
if wasmparser::validate(wasm, None).is_err() { | ||
return; | ||
} | ||
|
||
let isa = host_isa(); | ||
let mut compiler = Compiler::new(isa, compilation_strategy); | ||
let mut resolver = NullResolver {}; | ||
let global_exports = Rc::new(RefCell::new(HashMap::new())); | ||
let _ = CompiledModule::new(&mut compiler, wasm, &mut resolver, global_exports, false); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,50 +1,14 @@ | ||
#![no_main] | ||
|
||
extern crate libfuzzer_sys; | ||
|
||
use cranelift_codegen::settings; | ||
use libfuzzer_sys::fuzz_target; | ||
use std::cell::RefCell; | ||
use std::collections::HashMap; | ||
use std::rc::Rc; | ||
use wasmparser::validate; | ||
use wasmtime_jit::{CompilationStrategy, CompiledModule, Compiler, NullResolver}; | ||
use wasmtime_fuzzing::oracles; | ||
use wasmtime_jit::CompilationStrategy; | ||
|
||
fuzz_target!(|data: &[u8]| { | ||
if validate(data, None).is_err() { | ||
return; | ||
} | ||
let flag_builder = settings::builder(); | ||
let isa_builder = cranelift_native::builder().unwrap_or_else(|_| { | ||
panic!("host machine is not a supported target"); | ||
}); | ||
let isa = isa_builder.finish(settings::Flags::new(flag_builder)); | ||
let mut compiler = Compiler::new(isa, CompilationStrategy::Cranelift); | ||
let mut resolver = NullResolver {}; | ||
let global_exports = Rc::new(RefCell::new(HashMap::new())); | ||
let _compiled = | ||
match CompiledModule::new(&mut compiler, data, &mut resolver, global_exports, false) { | ||
Ok(x) => x, | ||
Err(_) => return, | ||
}; | ||
oracles::compile(data, CompilationStrategy::Cranelift); | ||
}); | ||
|
||
#[cfg(feature = "lightbeam")] | ||
fuzz_target!(|data: &[u8]| { | ||
if validate(data, None).is_err() { | ||
return; | ||
} | ||
let flag_builder = settings::builder(); | ||
let isa_builder = cranelift_native::builder().unwrap_or_else(|_| { | ||
panic!("host machine is not a supported target"); | ||
}); | ||
let isa = isa_builder.finish(settings::Flags::new(flag_builder)); | ||
let mut compiler = Compiler::new(isa, CompilationStrategy::Lightbeam); | ||
let mut resolver = NullResolver {}; | ||
let global_exports = Rc::new(RefCell::new(HashMap::new())); | ||
let _compiled = | ||
match CompiledModule::new(&mut compiler, data, &mut resolver, global_exports, false) { | ||
Ok(x) => x, | ||
Err(_) => return, | ||
}; | ||
oracles::compile(data, CompilationStrategy::Lightbeam); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,29 +1,9 @@ | ||
#![no_main] | ||
|
||
extern crate libfuzzer_sys; | ||
|
||
use cranelift_codegen::settings; | ||
use libfuzzer_sys::fuzz_target; | ||
use wasmparser::validate; | ||
use wasmtime_jit::{instantiate, CompilationStrategy, Compiler, NullResolver}; | ||
use wasmtime_fuzzing::oracles; | ||
use wasmtime_jit::{CompilationStrategy}; | ||
|
||
fuzz_target!(|data: &[u8]| { | ||
if validate(data, None).is_err() { | ||
return; | ||
} | ||
let flag_builder = settings::builder(); | ||
let isa_builder = cranelift_native::builder().unwrap_or_else(|_| { | ||
panic!("host machine is not a supported target"); | ||
}); | ||
let isa = isa_builder.finish(settings::Flags::new(flag_builder)); | ||
let mut compiler = Compiler::new(isa, CompilationStrategy::Auto); | ||
let mut imports_resolver = NullResolver {}; | ||
let _instance = instantiate( | ||
&mut compiler, | ||
data, | ||
&mut imports_resolver, | ||
Default::default(), | ||
true, | ||
) | ||
.unwrap(); | ||
oracles::instantiate(data, CompilationStrategy::Auto); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,27 +1,9 @@ | ||
#![no_main] | ||
|
||
extern crate libfuzzer_sys; | ||
|
||
use cranelift_codegen::settings; | ||
use libfuzzer_sys::fuzz_target; | ||
use wasmtime_jit::{instantiate, CompilationStrategy, Compiler, NullResolver}; | ||
use wasmtime_fuzzing::{generators, oracles}; | ||
use wasmtime_jit::CompilationStrategy; | ||
|
||
fuzz_target!(|data: &[u8]| { | ||
let binaryen_module = binaryen::tools::translate_to_fuzz_mvp(data); | ||
let wasm = binaryen_module.write(); | ||
let flag_builder = settings::builder(); | ||
let isa_builder = cranelift_native::builder().unwrap_or_else(|_| { | ||
panic!("host machine is not a supported target"); | ||
}); | ||
let isa = isa_builder.finish(settings::Flags::new(flag_builder)); | ||
let mut compiler = Compiler::new(isa, CompilationStrategy::Auto); | ||
let mut imports_resolver = NullResolver {}; | ||
let _instance = instantiate( | ||
&mut compiler, | ||
&wasm, | ||
&mut imports_resolver, | ||
Default::default(), | ||
true, | ||
) | ||
.unwrap(); | ||
fuzz_target!(|data: generators::WasmOptTtf| { | ||
oracles::instantiate(&data.wasm, CompilationStrategy::Auto); | ||
}); |