├── .github ├── FUNDING.yml └── workflows │ └── rust.yml ├── trophies ├── unwrap_panic_wain.wasm ├── SIGILL_wasm3.wasm ├── not_valid_wabt.wasm ├── alloc_failed_wain.wasm ├── hbo_export_wasm3.wasm ├── null_deref_wasm3.wasm ├── oob_read_Read_f64.wasm ├── reject_leb128_wabt.wasm ├── global_buffer_overflow.wasm ├── panic_oob_wasmer_clif.wasm ├── uaf_ReadLebUnsigned_wasm3.wasm ├── abort_wabt_reader_bad_alloc.wasm ├── huge_cpu_usage_wasmprinter.wasm ├── mem_alloc_failed_wasmprinter.wasm ├── segfault_binaryen_oob_read.wasm ├── assert_OnCallIndirectExpr_wabt.wasm ├── assert_failed_m3_compile_wasm3.wasm ├── assert_wasmtime_table_type_anyref.wasm ├── hbo_Compile_BlockStatements_2169.wasm ├── assert_OnReturnCallIndirectExpr_wabt.wasm └── assert_wasmtime_debug_simulated_dwarf.wasm ├── warf ├── debug │ ├── src │ │ └── lib.rs │ ├── Cargo.toml │ └── debug_template.rs ├── execute_all │ ├── src │ │ └── lib.rs │ ├── Cargo.toml │ └── exec_all_template.rs ├── fuzzers │ ├── rust-afl │ │ ├── src │ │ │ └── lib.rs │ │ ├── template.rs │ │ └── Cargo.toml │ ├── rust-honggfuzz │ │ ├── src │ │ │ └── lib.rs │ │ ├── Cargo.toml │ │ └── template.rs │ └── rust-libfuzzer │ │ ├── src │ │ └── lib.rs │ │ ├── fuzz │ │ ├── src │ │ │ └── lib.rs │ │ └── Cargo.toml │ │ ├── Cargo.toml │ │ └── template.rs ├── workspace │ └── corpora │ │ ├── wasm │ │ └── fib.wasm │ │ ├── wast │ │ └── add.wast │ │ └── wat │ │ └── fib.wat ├── targets │ ├── src │ │ ├── fizzy.rs │ │ ├── wasmprinter.rs │ │ ├── wat.rs │ │ ├── wasm3.rs │ │ ├── lightbeam.rs │ │ ├── wast.rs │ │ ├── parity_wasm.rs │ │ ├── wain.rs │ │ ├── binaryen_ffi.rs │ │ ├── cranelift.rs │ │ ├── wasmi.rs │ │ ├── wabt_ffi.rs │ │ ├── wasmparser.rs │ │ ├── wasmer.rs │ │ ├── wasmtime.rs │ │ └── lib.rs │ └── Cargo.toml ├── .dockerignore ├── Cargo.toml ├── src │ ├── env.rs │ ├── utils.rs │ ├── fuzzers.rs │ ├── exec_all.rs │ ├── debug.rs │ ├── main.rs │ ├── targets.rs │ └── rust_fuzzers.rs ├── Dockerfile ├── Makefile └── dictionary │ └── wast.dict ├── docs ├── INSTALL.md ├── how_to_add_new_fuzz_target.md ├── ROADMAP.md ├── warf_advanced_options.md ├── Internals.md ├── how_to_analyze_a_crash.md ├── WARF_SUBCOMMANDS.md └── INTEGRATION.md ├── .gitignore ├── README.md └── LICENSE /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: [pventuzelo] 2 | -------------------------------------------------------------------------------- /trophies/unwrap_panic_wain.wasm: -------------------------------------------------------------------------------- 1 | asm19asm195 -------------------------------------------------------------------------------- /warf/debug/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub fn make_cargo_happy() {} 2 | -------------------------------------------------------------------------------- /warf/execute_all/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub fn make_cargo_happy() {} 2 | -------------------------------------------------------------------------------- /warf/fuzzers/rust-afl/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub fn make_cargo_happy() {} 2 | -------------------------------------------------------------------------------- /warf/fuzzers/rust-honggfuzz/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub fn make_cargo_happy() {} 2 | -------------------------------------------------------------------------------- /warf/fuzzers/rust-libfuzzer/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub fn make_cargo_happy() {} 2 | -------------------------------------------------------------------------------- /warf/fuzzers/rust-libfuzzer/fuzz/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub fn make_cargo_happy() {} 2 | -------------------------------------------------------------------------------- /trophies/SIGILL_wasm3.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FuzzingLabs/wasm_runtimes_fuzzing/HEAD/trophies/SIGILL_wasm3.wasm -------------------------------------------------------------------------------- /trophies/not_valid_wabt.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FuzzingLabs/wasm_runtimes_fuzzing/HEAD/trophies/not_valid_wabt.wasm -------------------------------------------------------------------------------- /trophies/alloc_failed_wain.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FuzzingLabs/wasm_runtimes_fuzzing/HEAD/trophies/alloc_failed_wain.wasm -------------------------------------------------------------------------------- /trophies/hbo_export_wasm3.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FuzzingLabs/wasm_runtimes_fuzzing/HEAD/trophies/hbo_export_wasm3.wasm -------------------------------------------------------------------------------- /trophies/null_deref_wasm3.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FuzzingLabs/wasm_runtimes_fuzzing/HEAD/trophies/null_deref_wasm3.wasm -------------------------------------------------------------------------------- /trophies/oob_read_Read_f64.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FuzzingLabs/wasm_runtimes_fuzzing/HEAD/trophies/oob_read_Read_f64.wasm -------------------------------------------------------------------------------- /trophies/reject_leb128_wabt.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FuzzingLabs/wasm_runtimes_fuzzing/HEAD/trophies/reject_leb128_wabt.wasm -------------------------------------------------------------------------------- /trophies/global_buffer_overflow.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FuzzingLabs/wasm_runtimes_fuzzing/HEAD/trophies/global_buffer_overflow.wasm -------------------------------------------------------------------------------- /trophies/panic_oob_wasmer_clif.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FuzzingLabs/wasm_runtimes_fuzzing/HEAD/trophies/panic_oob_wasmer_clif.wasm -------------------------------------------------------------------------------- /warf/workspace/corpora/wasm/fib.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FuzzingLabs/wasm_runtimes_fuzzing/HEAD/warf/workspace/corpora/wasm/fib.wasm -------------------------------------------------------------------------------- /trophies/uaf_ReadLebUnsigned_wasm3.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FuzzingLabs/wasm_runtimes_fuzzing/HEAD/trophies/uaf_ReadLebUnsigned_wasm3.wasm -------------------------------------------------------------------------------- /trophies/abort_wabt_reader_bad_alloc.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FuzzingLabs/wasm_runtimes_fuzzing/HEAD/trophies/abort_wabt_reader_bad_alloc.wasm -------------------------------------------------------------------------------- /trophies/huge_cpu_usage_wasmprinter.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FuzzingLabs/wasm_runtimes_fuzzing/HEAD/trophies/huge_cpu_usage_wasmprinter.wasm -------------------------------------------------------------------------------- /trophies/mem_alloc_failed_wasmprinter.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FuzzingLabs/wasm_runtimes_fuzzing/HEAD/trophies/mem_alloc_failed_wasmprinter.wasm -------------------------------------------------------------------------------- /trophies/segfault_binaryen_oob_read.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FuzzingLabs/wasm_runtimes_fuzzing/HEAD/trophies/segfault_binaryen_oob_read.wasm -------------------------------------------------------------------------------- /trophies/assert_OnCallIndirectExpr_wabt.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FuzzingLabs/wasm_runtimes_fuzzing/HEAD/trophies/assert_OnCallIndirectExpr_wabt.wasm -------------------------------------------------------------------------------- /trophies/assert_failed_m3_compile_wasm3.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FuzzingLabs/wasm_runtimes_fuzzing/HEAD/trophies/assert_failed_m3_compile_wasm3.wasm -------------------------------------------------------------------------------- /trophies/assert_wasmtime_table_type_anyref.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FuzzingLabs/wasm_runtimes_fuzzing/HEAD/trophies/assert_wasmtime_table_type_anyref.wasm -------------------------------------------------------------------------------- /trophies/hbo_Compile_BlockStatements_2169.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FuzzingLabs/wasm_runtimes_fuzzing/HEAD/trophies/hbo_Compile_BlockStatements_2169.wasm -------------------------------------------------------------------------------- /trophies/assert_OnReturnCallIndirectExpr_wabt.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FuzzingLabs/wasm_runtimes_fuzzing/HEAD/trophies/assert_OnReturnCallIndirectExpr_wabt.wasm -------------------------------------------------------------------------------- /trophies/assert_wasmtime_debug_simulated_dwarf.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FuzzingLabs/wasm_runtimes_fuzzing/HEAD/trophies/assert_wasmtime_debug_simulated_dwarf.wasm -------------------------------------------------------------------------------- /warf/workspace/corpora/wast/add.wast: -------------------------------------------------------------------------------- 1 | (module 2 | (func $add (param i32) (param i32) (result i32) 3 | (get_local 0) 4 | (get_local 1) 5 | (i32.add) 6 | ) 7 | (export "add" (func $add)) 8 | ) 9 | -------------------------------------------------------------------------------- /warf/debug/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fuzz-targets-debug" 3 | version = "0.1.0" 4 | authors = ["Patrick Ventuzelo "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | fuzz-targets = {path = "../targets"} 9 | -------------------------------------------------------------------------------- /warf/fuzzers/rust-afl/template.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] extern crate afl; 2 | extern crate fuzz_targets; 3 | use fuzz_targets::fuzz_###TARGET### as fuzz_target; 4 | 5 | fn main() { 6 | fuzz!(|data| { 7 | fuzz_target(&data); 8 | }); 9 | } 10 | -------------------------------------------------------------------------------- /warf/fuzzers/rust-libfuzzer/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fuzz-targets-libfuzzer" 3 | version = "0.1.0" 4 | authors = ["Patrick Ventuzelo "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | fuzz-targets = {path = "../targets"} 9 | -------------------------------------------------------------------------------- /warf/fuzzers/rust-libfuzzer/template.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | 3 | #[macro_use] 4 | extern crate libfuzzer_sys; 5 | extern crate fuzz_targets; 6 | use fuzz_targets::fuzz_###TARGET### as fuzz_target; 7 | 8 | fuzz_target!(|data|{ 9 | fuzz_target(data); 10 | }); 11 | -------------------------------------------------------------------------------- /warf/fuzzers/rust-afl/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fuzz-targets-afl" 3 | version = "0.1.0" 4 | authors = ["Patrick Ventuzelo "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | fuzz-targets = {path = "../targets"} 9 | afl = "0.8.0" 10 | -------------------------------------------------------------------------------- /warf/execute_all/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fuzz-targets-exec-all" 3 | version = "0.1.0" 4 | authors = ["Patrick Ventuzelo "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | colored = "1.9" 9 | fuzz-targets = {path = "../targets"} 10 | -------------------------------------------------------------------------------- /warf/fuzzers/rust-honggfuzz/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fuzz-targets-honggfuzz" 3 | version = "0.1.0" 4 | authors = ["Patrick Ventuzelo "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | fuzz-targets = {path = "../targets"} 9 | honggfuzz = "0.5.49" 10 | -------------------------------------------------------------------------------- /warf/fuzzers/rust-honggfuzz/template.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate honggfuzz; 3 | extern crate fuzz_targets; 4 | use fuzz_targets::fuzz_###TARGET### as fuzz_target; 5 | 6 | fn main() { 7 | loop { 8 | fuzz!(|data| { 9 | fuzz_target(data); 10 | }) 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /warf/targets/src/fizzy.rs: -------------------------------------------------------------------------------- 1 | /*********************************************** 2 | fizzy 3 | - https://github.com/wasmx/fizzy 4 | ************************************************/ 5 | 6 | use fizzy::validate; 7 | 8 | pub fn fizzy_validate(data: &[u8]) -> bool { 9 | // Parse binary into syntax tree 10 | validate(&data) 11 | } 12 | -------------------------------------------------------------------------------- /warf/targets/src/wasmprinter.rs: -------------------------------------------------------------------------------- 1 | /*********************************************** 2 | wasmprinter 3 | - https://github.com/bytecodealliance/wasm-tools/tree/master/crates/wasmprinter 4 | ************************************************/ 5 | 6 | pub fn fuzz_wasmprinter_parser(data: &[u8]) -> bool { 7 | wasmprinter::print_bytes(&data).is_ok() 8 | } 9 | -------------------------------------------------------------------------------- /warf/.dockerignore: -------------------------------------------------------------------------------- 1 | # ignore .git and .cache folders 2 | .git 3 | .cache 4 | 5 | # ignore all markdown files (md) beside all README*.md other than README-secret.md 6 | *.md 7 | !README*.md 8 | 9 | # ignore all 10 | docs/ 11 | trophies/ 12 | 13 | # ignore all target folders and their contents 14 | target/* 15 | 16 | # ignore local corpora 17 | workspace/* -------------------------------------------------------------------------------- /warf/targets/src/wat.rs: -------------------------------------------------------------------------------- 1 | /*********************************************** 2 | wat 3 | - https://github.com/bytecodealliance/wasm-tools/tree/master/crates/wat 4 | ************************************************/ 5 | 6 | pub fn wat_parser(data: &[u8]) -> bool { 7 | let data = match std::str::from_utf8(&data) { 8 | Ok(o) => o, 9 | Err(_) => return false, 10 | }; 11 | wat::parse_str(&data).is_ok() 12 | } 13 | -------------------------------------------------------------------------------- /warf/fuzzers/rust-libfuzzer/fuzz/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fuzz-targets-libfuzzer" 3 | version = "0.1.0" 4 | authors = ["Patrick Ventuzelo "] 5 | edition = "2018" 6 | 7 | [package.metadata] 8 | cargo-fuzz = true 9 | 10 | # Prevent this from interfering with workspaces 11 | [workspace] 12 | members = ["."] 13 | 14 | [dependencies] 15 | fuzz-targets = {path = "../../targets"} 16 | libfuzzer-sys = "0.3" 17 | -------------------------------------------------------------------------------- /warf/targets/src/wasm3.rs: -------------------------------------------------------------------------------- 1 | /*********************************************** 2 | wasm3 (Rust binding using FFI) 3 | - https://github.com/Veykril/wasm3-rs 4 | ************************************************/ 5 | 6 | use wasm3::Environment; 7 | use wasm3::Module; 8 | 9 | pub fn fuzz_wasm3_parser_ffi(data: &[u8]) -> bool { 10 | let env = Environment::new().expect("Unable to create environment"); 11 | let _rt = env 12 | .create_runtime(1024 * 60) 13 | .expect("Unable to create runtime"); 14 | Module::parse(&env, &data).is_ok() 15 | } 16 | -------------------------------------------------------------------------------- /warf/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "warf" 3 | version = "0.1.0" 4 | authors = ["Patrick Ventuzelo "] 5 | edition = "2018" 6 | 7 | [[bin]] 8 | name = "warf" 9 | path = "src/main.rs" 10 | 11 | [dependencies] 12 | structopt = "0.2.7" 13 | clap = "2.33.0" 14 | regex = "1.3.6" 15 | failure = "0.1.7" 16 | strsim = "0.10.0" 17 | fs_extra = "1.1.0" 18 | strum = "0.18.0" 19 | strum_macros = "0.18.0" 20 | 21 | [workspace] 22 | exclude = [ 23 | "targets", 24 | "execute_all", 25 | "debug", 26 | "fuzzers", 27 | "workspace" 28 | ] 29 | -------------------------------------------------------------------------------- /warf/targets/src/lightbeam.rs: -------------------------------------------------------------------------------- 1 | /*********************************************** 2 | LIGHTBEAM: 3 | - https://github.com/bytecodealliance/wasmtime/tree/master/crates/lightbeam 4 | ***********************************************/ 5 | 6 | /// Fuzzing `lightbeam::translate` using translate methods. 7 | /// 8 | /// NOTE: lightbeam not called the same way here than in wasmtime. 9 | /// NOTE: I'm not sure this method validate the module first. 10 | pub fn fuzz_lightbeam_translate(data: &[u8]) -> bool { 11 | use lightbeam::translate; 12 | 13 | translate(&data).is_ok() 14 | } 15 | -------------------------------------------------------------------------------- /warf/targets/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fuzz-targets" 3 | version = "0.1.0" 4 | authors = ["Patrick Ventuzelo "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | wasmi = "*" 9 | wasmi-validation = "*" 10 | parity-wasm = "0.41.0" 11 | wasmer-runtime = "*" 12 | wasmer-singlepass-backend = "*" 13 | wasmtime = "*" 14 | # lightbeam = "*" 15 | wasmparser = "*" 16 | binaryen = "*" 17 | wabt = "*" 18 | wasmprinter = "*" 19 | wain-validate = "*" 20 | wain-syntax-binary = "*" 21 | wat = "*" 22 | wast = "*" 23 | wasm3 = { git = "https://github.com/Veykril/wasm3-rs", features=["build-bindgen"]} 24 | fizzy = "0.6.0-dev" 25 | -------------------------------------------------------------------------------- /warf/workspace/corpora/wat/fib.wat: -------------------------------------------------------------------------------- 1 | (module 2 | (type (;0;) (func (param i32) (result i32))) 3 | (func (;0;) (type 0) (param i32) (result i32) 4 | block ;; label = @1 5 | local.get 0 6 | i32.const 1 7 | i32.or 8 | i32.const 1 9 | i32.ne 10 | br_if 0 (;@1;) 11 | local.get 0 12 | return 13 | end 14 | local.get 0 15 | i32.const -1 16 | i32.add 17 | call 0 18 | local.get 0 19 | i32.const -2 20 | i32.add 21 | call 0 22 | i32.add) 23 | (table (;0;) 0 funcref) 24 | (memory (;0;) 1) 25 | (export "memory" (memory 0)) 26 | (export "fib" (func 0))) 27 | -------------------------------------------------------------------------------- /warf/targets/src/wast.rs: -------------------------------------------------------------------------------- 1 | /*********************************************** 2 | wast 3 | - https://github.com/bytecodealliance/wasm-tools/tree/master/crates/wast 4 | ************************************************/ 5 | 6 | pub fn wast_parser(data: &[u8]) -> bool { 7 | use wast::parser::{self, ParseBuffer}; 8 | use wast::Wat; 9 | 10 | let data = match std::str::from_utf8(&data) { 11 | Ok(o) => o, 12 | Err(_) => return false, 13 | }; 14 | 15 | let buf = match ParseBuffer::new(&data) { 16 | Ok(o) => o, 17 | Err(_) => return false, 18 | }; 19 | parser::parse::(&buf).is_ok() 20 | } 21 | -------------------------------------------------------------------------------- /warf/targets/src/parity_wasm.rs: -------------------------------------------------------------------------------- 1 | /*********************************************** 2 | parity-wasm: 3 | - https://github.com/paritytech/parity-wasm 4 | ************************************************/ 5 | 6 | /// Fuzzing `parity_wasm::deserialize_buffer`. 7 | /// 8 | /// TODO: Will be more useful with calls to `parity_wasm::elements::Module` accessors. 9 | /// NOTE: wasmi already use this function in `wasmi::Module::from_buffer`. 10 | pub fn parity_wasm_deserialize(data: &[u8]) -> bool { 11 | use parity_wasm::{deserialize_buffer, elements}; 12 | 13 | let module: std::result::Result = deserialize_buffer(&data); 14 | module.is_ok() 15 | } 16 | -------------------------------------------------------------------------------- /warf/targets/src/wain.rs: -------------------------------------------------------------------------------- 1 | /*********************************************** 2 | wain 3 | - https://github.com/rhysd/wain 4 | ************************************************/ 5 | 6 | use wain_syntax_binary::parse; 7 | use wain_validate::validate; 8 | 9 | pub fn fuzz_wain_parser(data: &[u8]) -> bool { 10 | // Parse binary into syntax tree 11 | match parse(&data) { 12 | Ok(_) => true, 13 | Err(_) => false, 14 | } 15 | } 16 | 17 | pub fn fuzz_wain_validate(data: &[u8]) -> bool { 18 | // Parse binary into syntax tree 19 | match parse(&data) { 20 | // Validate module 21 | Ok(tree) => validate(&tree).is_ok(), 22 | Err(_) => false, 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /warf/src/env.rs: -------------------------------------------------------------------------------- 1 | use failure::{Error, ResultExt}; 2 | use std::env; 3 | use std::fs; 4 | use std::path::PathBuf; 5 | 6 | pub fn root_dir() -> Result { 7 | let p = env::var("CARGO_MANIFEST_DIR") 8 | .map(From::from) 9 | .or_else(|_| env::current_dir())?; 10 | Ok(p) 11 | } 12 | 13 | pub fn targets_dir() -> Result { 14 | let p = root_dir()?.join("targets"); 15 | Ok(p) 16 | } 17 | 18 | pub fn workspace_dir() -> Result { 19 | let p = root_dir()?.join("workspace"); 20 | fs::create_dir_all(&p).context("unable to create workspace dir".to_string())?; 21 | Ok(p) 22 | } 23 | 24 | pub fn corpora_dir() -> Result { 25 | let p = workspace_dir()?.join("corpora"); 26 | Ok(p) 27 | } 28 | -------------------------------------------------------------------------------- /warf/targets/src/binaryen_ffi.rs: -------------------------------------------------------------------------------- 1 | /*********************************************** 2 | BINARYEN (Rust binding using FFI) 3 | - https://github.com/pepyakin/binaryen-rs 4 | ************************************************/ 5 | 6 | /// Fuzzing `binaryen::Module` read 7 | /// 8 | /// NOTE: We are fuzzing binaryen over FFI. 9 | /// TODO: Verify that binary contains coverage for C++ code of binaryen. 10 | pub fn fuzz_binaryen_ffi(data: &[u8]) -> bool { 11 | use binaryen::Module; 12 | 13 | Module::read(&data).is_ok() 14 | } 15 | 16 | pub fn fuzz_binaryen_optimize_ffi(data: &[u8]) -> bool { 17 | use binaryen::{CodegenConfig, Module}; 18 | 19 | let mut module = match Module::read(&data) { 20 | Ok(o) => o, 21 | Err(_) => return false, 22 | }; 23 | let config = CodegenConfig { 24 | optimization_level: 4, 25 | shrink_level: 0, 26 | debug_info: true, 27 | }; 28 | module.optimize(&config); 29 | true 30 | } 31 | -------------------------------------------------------------------------------- /docs/INSTALL.md: -------------------------------------------------------------------------------- 1 | # Installation 2 | 3 | Following installation steps are working for `Ubuntu 18.04`. 4 | 5 | - Install Rust nightly 6 | ``` sh 7 | # Install Rust and Cargo 8 | curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain nightly 9 | ``` 10 | 11 | - Install system dependencies (Ubuntu/Debian): 12 | ``` sh 13 | # Install LLVM 14 | sudo apt install -y llvm curl 15 | 16 | # Install honggfuzz-rs and subcommand in cargo 17 | sudo apt install -y build-essential binutils-dev libunwind-dev libblocksruntime-dev 18 | cargo +nightly install --force honggfuzz 19 | 20 | # Install cargo-fuzz (libfuzzer for Rust) and subcommand in cargo 21 | cargo +nightly install --force cargo-fuzz 22 | 23 | # Install afl-rs and subcommand in cargo 24 | sudo apt install -y build-essential libtool-bin python3 cmake automake bison libglib2.0-dev libpixman-1-dev clang python-setuptools llvm 25 | cargo +nightly install --force afl 26 | ``` 27 | 28 | You're good to go now, build warf with `make build` ;) 29 | -------------------------------------------------------------------------------- /warf/debug/debug_template.rs: -------------------------------------------------------------------------------- 1 | extern crate fuzz_targets; 2 | use fuzz_targets::fuzz_###TARGET### as fuzz_target; 3 | 4 | use std::env; 5 | use std::fs::File; 6 | use std::io; 7 | use std::io::Read; 8 | 9 | /// Read the contents from file path 10 | fn read_contents_from_path(path_str: &String) -> Result, io::Error> { 11 | let mut buffer: Vec = Vec::new(); 12 | let file_path = std::path::PathBuf::from(path_str); 13 | 14 | println!("file_to_process: {:?}", file_path); 15 | 16 | let mut file = File::open(file_path)?; 17 | file.read_to_end(&mut buffer)?; 18 | drop(file); 19 | Ok(buffer) 20 | } 21 | 22 | fn main() { 23 | println!("Start debugging of ###TARGET###"); 24 | let args: Vec = env::args().collect(); 25 | 26 | // verify file_to_process is provided 27 | if args.len() != 2 { 28 | println!("Usage: ###TARGET### \n"); 29 | return; 30 | } 31 | 32 | // read data from provided file 33 | let data = read_contents_from_path(&args[1]).expect("cannot read file content"); 34 | 35 | // call the fuzzing target 36 | fuzz_target(&data); 37 | 38 | println!("No crash, everything is OK\n"); 39 | } 40 | -------------------------------------------------------------------------------- /warf/targets/src/cranelift.rs: -------------------------------------------------------------------------------- 1 | /*********************************************** 2 | CRANELIFT-WASM: 3 | - https://github.com/bytecodealliance/wasmtime/tree/master/cranelift/wasm 4 | 5 | ************************************************/ 6 | 7 | // TODO - Fuzzing cranelift generation on other ISA. 8 | /* 9 | 10 | 11 | // Add to Cargo.toml 12 | #cranelift-wasm = "0.62.0" 13 | #cranelift-codegen = "0.62.0" 14 | #target-lexicon = "0.10" 15 | 16 | 17 | pub fn TODO_fuzz_cranelift_wasm_translate_module(data: &[u8]) { 18 | use cranelift_wasm::{translate_module, DummyEnvironment, ReturnMode}; 19 | use cranelift_codegen::isa; 20 | use cranelift_codegen::settings::{self, Flags}; 21 | use target_lexicon::triple; 22 | use std::str::FromStr; 23 | 24 | let flags = Flags::new(settings::builder()); 25 | let triple = triple!("x86_64"); 26 | let isa = isa::lookup(triple).unwrap().finish(flags.clone()); 27 | let return_mode = ReturnMode::NormalReturns; 28 | let mut dummy_environ = DummyEnvironment::new(isa.frontend_config(), return_mode, false); 29 | 30 | let _ = translate_module(data.as_ref(), &mut dummy_environ); 31 | } 32 | 33 | */ 34 | 35 | // TODO - differential fuzzing 36 | // TODO - structural fuzzing -------------------------------------------------------------------------------- /warf/targets/src/wasmi.rs: -------------------------------------------------------------------------------- 1 | /*********************************************** 2 | wasmi: 3 | - https://github.com/paritytech/wasmi 4 | ************************************************/ 5 | 6 | /// Fuzzing `wasmi::validate_module`. 7 | pub fn wasmi_validate(data: &[u8]) -> bool { 8 | use parity_wasm::{deserialize_buffer, elements}; 9 | use wasmi_validation::{validate_module, PlainValidator}; 10 | 11 | let module: elements::Module = match deserialize_buffer(&data) { 12 | Ok(module) => module, 13 | _ => return false, 14 | }; 15 | validate_module::(&module).is_ok() 16 | } 17 | 18 | /// Fuzzing `wasmi::ModuleInstance` with default `ImportsBuilder`. 19 | pub fn wasmi_instantiate(data: &[u8]) -> bool { 20 | use wasmi::{ImportsBuilder, Module, ModuleInstance}; 21 | 22 | match Module::from_buffer(&data) { 23 | Ok(module) => ModuleInstance::new(&module, &ImportsBuilder::default()).is_ok(), 24 | _ => false, 25 | } 26 | 27 | // TODO(RM3): add calls to instance functions like: 28 | // - invoke_export: https://github.com/paritytech/wasmi/blob/b67af25899874de7aac187e08e3b2a30d9bbc388/benches/src/lib.rs#L38 29 | // - run_start: https://github.com/paritytech/wasmi/blob/899cc32e45483fce12907f807ee9b09d837d2636/examples/interpret.rs#L36 30 | } 31 | -------------------------------------------------------------------------------- /warf/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:18.04 2 | 3 | ARG RUST_TOOLCHAIN="nightly" 4 | 5 | ENV CARGO_HOME=/usr/local/rust 6 | ENV RUSTUP_HOME=/usr/local/rust 7 | ENV PATH="$PATH:$CARGO_HOME/bin" 8 | 9 | # Update ubuntu 10 | RUN apt-get update && \ 11 | apt-get install -y \ 12 | llvm \ 13 | curl \ 14 | build-essential \ 15 | binutils-dev \ 16 | libunwind-dev \ 17 | libblocksruntime-dev \ 18 | libtool-bin \ 19 | python3 \ 20 | cmake automake \ 21 | bison libglib2.0-dev \ 22 | libpixman-1-dev clang \ 23 | python-setuptools 24 | 25 | # Install Rust and Cargo 26 | RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain "$RUST_TOOLCHAIN" 27 | 28 | # Install honggfuzz-rs and subcommand in cargo 29 | RUN cargo +nightly install --force honggfuzz 30 | # Install cargo-fuzz (libfuzzer for Rust) and subcommand in cargo 31 | RUN cargo +nightly install --force cargo-fuzz 32 | # Install afl-rs and subcommand in cargo 33 | RUN cargo +nightly install --force afl 34 | 35 | # create a new empty shell project 36 | RUN USER=root cargo new --bin warf 37 | WORKDIR /warf 38 | 39 | # copy over your manifests 40 | # COPY ./Cargo.lock ./Cargo.lock 41 | COPY ./Cargo.toml ./Cargo.toml 42 | 43 | # this build step will cache your dependencies 44 | RUN cargo build 45 | RUN rm src/*.rs 46 | 47 | # Copy all 48 | COPY . . 49 | 50 | # Build the CLI tool 51 | RUN make build 52 | 53 | ENTRYPOINT ["./warf"] -------------------------------------------------------------------------------- /warf/targets/src/wabt_ffi.rs: -------------------------------------------------------------------------------- 1 | /*********************************************** 2 | WABT (Rust binding using FFI) 3 | - https://github.com/pepyakin/wabt-rs 4 | ************************************************/ 5 | 6 | /// Fuzzing `wabt::wasm2wat_with_features` with all features enabled. 7 | /// 8 | /// NOTE: We are fuzzing binaryen over FFI. 9 | /// TODO: Verify if this implementation validate module first. 10 | /// TODO: Verify that binary contains coverage for C++ code of wabt. 11 | pub fn fuzz_wabt_wasm2wat_all_feat_ffi(data: &[u8]) -> bool { 12 | use wabt::{wasm2wat_with_features, Features}; 13 | 14 | let mut features = Features::new(); 15 | features.enable_all(); 16 | wasm2wat_with_features(&data, features).is_ok() 17 | } 18 | 19 | /// Fuzzing `wabt::Module::{read_binary, validate}` with default features. 20 | pub fn fuzz_wabt_validate_ffi(data: &[u8]) -> bool { 21 | use wabt::{Module, ReadBinaryOptions}; 22 | 23 | // Default wasm features sets by `Module::read_binary`. 24 | match Module::read_binary(&data, &ReadBinaryOptions::default()) { 25 | Ok(module) => module.validate().is_ok(), 26 | _ => false, 27 | } 28 | } 29 | 30 | pub fn fuzz_wabt_wat2wasm_ffi(data: &[u8]) -> bool { 31 | use wabt::{wat2wasm_with_features, Features}; 32 | 33 | let mut features = Features::new(); 34 | features.enable_all(); 35 | 36 | wat2wasm_with_features(&data, features).is_ok() 37 | } 38 | 39 | // TODO(RM4) - Module::parse_wat 40 | -------------------------------------------------------------------------------- /warf/targets/src/wasmparser.rs: -------------------------------------------------------------------------------- 1 | /*********************************************** 2 | WASMPARSER: 3 | - https://github.com/bytecodealliance/wasmparser 4 | ************************************************/ 5 | 6 | /// `Fuzzing wasmparser::Parser` and loop to read all module. 7 | pub fn fuzz_wasmparser_parser(data: &[u8]) -> bool { 8 | use wasmparser::Parser; 9 | let res_iter = Parser::new(0).parse_all(&data); 10 | for res in res_iter { 11 | match res { 12 | Err(_) => return false, 13 | _ => (), 14 | } 15 | } 16 | true 17 | } 18 | 19 | /// Fuzzing `wasmparser::ValidatingParser` and loop to read all module. 20 | pub fn fuzz_wasmparser_validate(data: &[u8]) -> bool { 21 | use wasmparser::validate; 22 | 23 | validate(&data).is_ok() 24 | } 25 | 26 | /// Fuzzing `wasmparser::ValidatingParser` with all features enabled and loop to read all module. 27 | pub fn fuzz_wasmparser_validate_all_feat(data: &[u8]) -> bool { 28 | use wasmparser::{Validator, WasmFeatures}; 29 | 30 | let mut validator = Validator::new(); 31 | validator.wasm_features(WasmFeatures { 32 | reference_types: true, 33 | multi_value: true, 34 | threads: true, 35 | simd: true, 36 | module_linking: true, 37 | tail_call: true, 38 | bulk_memory: true, 39 | deterministic_only: true, 40 | multi_memory: true, 41 | memory64: true, 42 | }); 43 | 44 | // validate 45 | validator.validate_all(&data).is_ok() 46 | } 47 | -------------------------------------------------------------------------------- /warf/src/utils.rs: -------------------------------------------------------------------------------- 1 | use failure::Error; 2 | use std::path::PathBuf; 3 | 4 | pub fn copy_dir(from: PathBuf, to: PathBuf) -> Result<(), Error> { 5 | use fs_extra::dir::{copy, CopyOptions}; 6 | let mut options = CopyOptions::new(); 7 | 8 | options.overwrite = true; 9 | options.skip_exist = true; 10 | options.copy_inside = true; 11 | copy(from, to, &options)?; 12 | Ok(()) 13 | } 14 | 15 | /// Produces a string from a given list of possible values which is similar to 16 | /// the passed in value `v` with a certain confidence. 17 | /// Thus in a list of possible values like ["foo", "bar"], the value "fop" will yield 18 | /// `Some("foo")`, whereas "blark" would yield `None`. 19 | /// 20 | /// Originally from [clap] which is Copyright (c) 2015-2016 Kevin B. Knapp 21 | /// 22 | /// [clap]: https://github.com/kbknapp/clap-rs/blob/dc7ae65fb784dc355d56f09554f1216b22755c3e/src/suggestions.rs 23 | pub fn did_you_mean<'a, T: ?Sized, I>(v: &str, possible_values: I) -> Option<&'a str> 24 | where 25 | T: AsRef + 'a, 26 | I: IntoIterator, 27 | { 28 | extern crate strsim; 29 | 30 | let mut candidate: Option<(f64, &str)> = None; 31 | for pv in possible_values { 32 | let confidence = strsim::jaro_winkler(v, pv.as_ref()); 33 | if confidence > 0.8 && (candidate.is_none() || (candidate.as_ref().unwrap().0 < confidence)) 34 | { 35 | candidate = Some((confidence, pv.as_ref())); 36 | } 37 | } 38 | match candidate { 39 | None => None, 40 | Some((_, candidate)) => Some(candidate), 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /warf/execute_all/exec_all_template.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused)] 2 | extern crate fuzz_targets; 3 | use fuzz_targets::*; 4 | 5 | use std::env; 6 | use std::fs::File; 7 | use std::io; 8 | use std::io::Read; 9 | 10 | use colored::*; 11 | 12 | use std::time::Instant; 13 | 14 | /// Read the contents from file path 15 | fn read_contents_from_path(path_str: &String) -> Result, io::Error> { 16 | let mut buffer: Vec = Vec::new(); 17 | let file_path = std::path::PathBuf::from(path_str); 18 | 19 | println!("file_to_process: {:?}\n", file_path); 20 | 21 | let mut file = File::open(file_path)?; 22 | file.read_to_end(&mut buffer)?; 23 | drop(file); 24 | Ok(buffer) 25 | } 26 | 27 | fn log_benchmark(it: Instant) { 28 | let elapsed = (Instant::now() - it).as_secs_f64(); 29 | println!("{}", format!("benchmark (sec): {:5.10}", elapsed / 1024.).yellow()); 30 | } 31 | 32 | fn is_ok(target: String, res: bool) { 33 | if res { 34 | println!("{}", format!("[O] {}: Ok()", target).green()); 35 | } else { 36 | println!("{}", format!("[X] {}: Err()", target).red()); 37 | } 38 | } 39 | 40 | fn main() { 41 | println!("Execution of all runtime engine"); 42 | let args: Vec = env::args().collect(); 43 | 44 | // verify file_to_process is provided 45 | if args.len() != 2 { 46 | println!("Usage: {} \n", &args[0]); 47 | return; 48 | } 49 | 50 | // read data from provided file 51 | let data = read_contents_from_path(&args[1]).expect("cannot read file content"); 52 | 53 | // call all fuzzing targets 54 | ###TARGETS### 55 | 56 | println!("\nNo crash, everything is OK\n"); 57 | } 58 | -------------------------------------------------------------------------------- /warf/targets/src/wasmer.rs: -------------------------------------------------------------------------------- 1 | /*********************************************** 2 | WASMER: 3 | - https://github.com/wasmerio/wasmer 4 | ************************************************/ 5 | 6 | /// Fuzzing `wasmer::validate` 7 | pub fn fuzz_wasmer_validate(data: &[u8]) -> bool { 8 | extern crate wasmer_runtime; 9 | wasmer_runtime::validate(&data) 10 | } 11 | 12 | /// Fuzzing wasmer::compile with Cranelift compiler backend 13 | pub fn fuzz_wasmer_compile_clif(data: &[u8]) -> bool { 14 | use wasmer_runtime::compile; 15 | compile(&data).is_ok() 16 | } 17 | 18 | /// Fuzzing `wasmer::compile` with `SinglePass` compiler backend 19 | pub fn fuzz_wasmer_compile_singlepass(data: &[u8]) -> bool { 20 | use wasmer_runtime::compile_with; 21 | use wasmer_singlepass_backend::SinglePassCompiler; 22 | compile_with(&data, &SinglePassCompiler::new()).is_ok() 23 | } 24 | 25 | /// Fuzzing `wasmer::instantiate` with empty import_object 26 | pub fn fuzz_wasmer_instantiate(data: &[u8]) -> bool { 27 | use wasmer_runtime::{imports, instantiate}; 28 | let import_object = imports! {}; 29 | // allow_missing_functions should prevent wasmer to reject 30 | // modules with imported functions but generate more false positive bugs 31 | // import_object.allow_missing_functions = true; 32 | instantiate(&data, &import_object).is_ok() 33 | 34 | // TODO(RM3): improve or create new fuzz harness that iterate 35 | // over module functions and call them all 36 | } 37 | 38 | /* 39 | 40 | // TODO: LLVMCompiler not available throw crates.io 41 | pub fn TODO_fuzz_wasmer_compile_llvm(data: &[u8]) { 42 | extern crate wasmer_runtime; 43 | use std::str::FromStr; 44 | use wasmer_runtime::{compiler_for_backend, compile_with, Backend}; 45 | // LLVM backend 46 | let backend = match Backend::from_str("llvm"){ 47 | Ok(backend) => backend, 48 | _ => return, 49 | }; 50 | let compiler = match compiler_for_backend(backend) { 51 | Some(compiler) => compiler, 52 | _ => return, 53 | }; 54 | let _res = compile_with(&data, compiler.as_ref()); 55 | } 56 | 57 | // TODO(RM3) - wasmer_runtime::validate_and_report_errors_with_features 58 | */ 59 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # specific to this project 2 | 3 | Cargo.lock 4 | warf/workspace/* 5 | warf/warf 6 | 7 | # Byte-compiled / optimized / DLL files 8 | __pycache__/ 9 | *.py[cod] 10 | *$py.class 11 | 12 | # C extensions 13 | *.so 14 | 15 | # Distribution / packaging 16 | .Python 17 | build/ 18 | develop-eggs/ 19 | dist/ 20 | downloads/ 21 | eggs/ 22 | .eggs/ 23 | lib/ 24 | lib64/ 25 | parts/ 26 | sdist/ 27 | var/ 28 | wheels/ 29 | pip-wheel-metadata/ 30 | share/python-wheels/ 31 | *.egg-info/ 32 | .installed.cfg 33 | *.egg 34 | MANIFEST 35 | 36 | # PyInstaller 37 | # Usually these files are written by a python script from a template 38 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 39 | *.manifest 40 | *.spec 41 | 42 | # Installer logs 43 | pip-log.txt 44 | pip-delete-this-directory.txt 45 | 46 | # Unit test / coverage reports 47 | htmlcov/ 48 | .tox/ 49 | .nox/ 50 | .coverage 51 | .coverage.* 52 | .cache 53 | nosetests.xml 54 | coverage.xml 55 | *.cover 56 | *.py,cover 57 | .hypothesis/ 58 | .pytest_cache/ 59 | 60 | # Translations 61 | *.mo 62 | *.pot 63 | 64 | # Django stuff: 65 | *.log 66 | local_settings.py 67 | db.sqlite3 68 | db.sqlite3-journal 69 | 70 | # Flask stuff: 71 | instance/ 72 | .webassets-cache 73 | 74 | # Scrapy stuff: 75 | .scrapy 76 | 77 | # Sphinx documentation 78 | docs/_build/ 79 | 80 | # PyBuilder 81 | target/ 82 | 83 | # Jupyter Notebook 84 | .ipynb_checkpoints 85 | 86 | # IPython 87 | profile_default/ 88 | ipython_config.py 89 | 90 | # pyenv 91 | .python-version 92 | 93 | # pipenv 94 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 95 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 96 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 97 | # install all needed dependencies. 98 | #Pipfile.lock 99 | 100 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 101 | __pypackages__/ 102 | 103 | # Celery stuff 104 | celerybeat-schedule 105 | celerybeat.pid 106 | 107 | # SageMath parsed files 108 | *.sage.py 109 | 110 | # Environments 111 | .env 112 | .venv 113 | env/ 114 | venv/ 115 | ENV/ 116 | env.bak/ 117 | venv.bak/ 118 | 119 | # Spyder project settings 120 | .spyderproject 121 | .spyproject 122 | 123 | # Rope project settings 124 | .ropeproject 125 | 126 | # mkdocs documentation 127 | /site 128 | 129 | # mypy 130 | .mypy_cache/ 131 | .dmypy.json 132 | dmypy.json 133 | 134 | # Pyre type checker 135 | .pyre/ 136 | -------------------------------------------------------------------------------- /docs/how_to_add_new_fuzz_target.md: -------------------------------------------------------------------------------- 1 | # How to integrate a new target/project? 2 | 3 | In this example, we will learn how to integrate `wasmer` to warf and fuzz the `wasmer_runtime::validate` method. 4 | 5 | ## 1. Add the target to `Cargo.toml` 6 | 7 | First, we need to: 8 | - Open the file `warf/targets/Cargo.toml`. 9 | - Add `wasmer-runtime = "0.16.2"` to `dependencies` section. 10 | 11 | Example: 12 | ``` rust 13 | [dependencies] 14 | wasmer-runtime = "0.16.2" 15 | ``` 16 | 17 | ## 2. Create the fuzzing function. 18 | 19 | Secondly, we need to create our fuzzing function: 20 | - Create a new file inside `warf/targets/src/` (e.g `wasmer.rs`) 21 | - Create a new public function. 22 | - You can add `extern crate` inside the function but it's not always mandatory. 23 | - Call the targetted function and provide `data` to it. 24 | 25 | Example: 26 | ``` rust 27 | pub fn wasmer_validate(data: &[u8]) { 28 | extern crate wasmer_runtime; 29 | let _ = wasmer_runtime::validate(&data); 30 | } 31 | ``` 32 | 33 | Make this function public for fuzzers: 34 | - Open the file `warf/targets/src/lib.rs`. 35 | - add `mod` followed by the name of your previous file. 36 | - add a public function starting with the name `fuzz_` followed by target name. 37 | - Inside this function, call the function you want to fuzz inside `wasmer.rs` 38 | 39 | Example: 40 | ``` rust 41 | mod wasmer; 42 | pub fn fuzz_wasmer_validate(data: &[u8]) { 43 | wasmer::wasmer_validate(data); 44 | } 45 | ``` 46 | 47 | ## 3. Add your new target inside warf targets 48 | 49 | - Open `warf/src/targets.rs`: 50 | - add a new line into the `Targets` enum (e.g `WasmerValidate`) 51 | 52 | - add the fuzzing function name (without the `fuzz_`) inside `fn name(&self)` (e.g `Targets::WasmerValidate => "wasmer_validate",`) 53 | 54 | - associate the name of the corpora folder to your targer (e.g `Targets::DiffInstantiate => "wasm"`) 55 | 56 | - add your target to `fn template` and `fn language`. 57 | 58 | - build `warf` using `make build`. 59 | 60 | ## 4. Verify your target is available 61 | 62 | Additionnaly, you can verify this new target is listed when using warf `list` subcommand. 63 | 64 | ``` sh 65 | $ ./warf list 66 | parity_wasm_deserialize 67 | [...] 68 | wasmer_validate 69 | ``` 70 | 71 | ## 5. Test your target (with `warf debug` subcommand) 72 | 73 | Verify that your target is working properly using the warf `debug` subcommand. 74 | 75 | ``` sh 76 | $ ./warf debug wasmer_validate 77 | [...] 78 | Finished dev [unoptimized + debuginfo] target(s) in 2.47s 79 | $ ./workspace/debug/target/debug/debug_wasmer_validate ./workspace/corpora/wasm/fib.wasm 80 | Start wasmer_validate debug 81 | file_path: "./workspace/corpora/wasm/fib.wasm" 82 | Everything is OK 83 | ``` 84 | 85 | ## 6. Start fuzzing 86 | 87 | ``` sh 88 | $ ./warf target wasmer_validate 89 | ``` 90 | -------------------------------------------------------------------------------- /docs/ROADMAP.md: -------------------------------------------------------------------------------- 1 | # Roadmap 2 | 3 | ## Roadmap #1 (DONE) 4 | 5 | 1. Integration Plan / List of major WebAssembly runtimes and APIs to interact with them. - [DONE](INTEGRATION.md) 6 | 2. Project development / Development of the project base (architecture and interface) - [DONE](../warf/src/main.rs) 7 | 3. APIs / Creation of integration APIs + documentation - [DONE](../warf/targets/src/lib.rs) / [DONE](how_to_add_new_fuzz_target.md) 8 | 4. Delivery report / Tutorial for project installation and testings - [DONE](../README.md#quick-start) 9 | 10 | ## Roadmap #2 (DONE) 11 | 12 | 1. Runtimes Integration / Integration of main runtimes engines. - [DONE](../warf/targets/src/lib.rs) 13 | 2. CLI tool / Command line tool allowing execution of wasm modules through all runtimes. - [DONE - ./warf execute-all, make test](../warf/src/main.rs) 14 | 3. Project development / Improvement of the project (threading, runtimes perf monitoring) - [DONE - benchmark subcommand, make test-bench](../warf/src/main.rs) 15 | 4. Project development / Development of fuzzing harness per runtimes. - [DONE](../warf/targets/src/) 16 | 5. Runtimes dockers / Dockers to install runtimes engines easily - [DONE](../Dockerfile) 17 | 6. Delivery reports / Tutorial for runtimes installation, compilation, how to run tools and unittests - [DONE](../README.md) / [DONE](WARF_SUBCOMMANDS.md) / [DONE](../docs/) 18 | 7. Unittest / Unittest to verify runtimes engines work as expected - [DONE - make test\*](../warf/Makefile) 19 | 20 | ## Roadmap #3 (DONE) 21 | 22 | 1. Project development / Evaluation fuzzing hardness + improvement - [DONE - Add more fuzzing targets ([wasmprinter](../warf/targets/src/wasmprinter.rs), [wain](../warf/targets/src/wain.rs), [wat](../warf/targets/src/wat.rs), [wast](../warf/targets/src/wast.rs), [wasm3](../warf/targets/src/wasm3.rs))] 23 | 2. Fuzzing Implementation / Differential fuzzing implementation for wasm runtimes and parsers. - [DONE](../warf/targets/src/lib.rs) 24 | 3. Fuzzing Implementation / Grammar fuzzing implementation specific to WebAssembly module - [DONE - dictionary option](../warf/dictionary) 25 | 4. Project development / Improvement of the fuzzing (input file sharing, mutation algorithm, speed). - [DONE - sharing folder for samples](../warf/src/targets.rs) 26 | 5. Delivery reports / Tutorial for running fuzzers and use advanced CLI options - [DONE](warf_advanced_options.md) 27 | 6. Unittest / unit test to verify fuzzing is deterministic and reproductible - [DONE - seed option make fuzzing reproduc mis make](../warf/src/main.rs) 28 | 29 | ## Roadmap #4 (DONE) 30 | 31 | 1. Tutorial / Runtime integration tutorial - [DONE - how_to_add_new_fuzz_target.md](how_to_add_new_fuzz_target.md) 32 | 2. Tutorial / Utilisation tutorial - DONE [WARF_SUBCOMMANDS.md](WARF_SUBCOMMANDS.md), [warf_advanced_options.md](warf_advanced_options.md) 33 | 3. Documentation / Internal architecture - [DONE - Internals.md](Internals.md#global-functionnement) 34 | 4. Documentation / Details fuzzing engines & techniques - [DONE - Internals.md](Internals.md#fuzzing-engines) 35 | 5. Performance testing / Improve fuzzing performances and benchmarks - [DONE - Leveraging Rust borrowing to improve fuzzing performances](https://github.com/pventuzelo/wasm_runtimes_fuzzing/commit/7b47782f01187571446f2f2d376a1d6183ee68ff) 36 | -------------------------------------------------------------------------------- /docs/warf_advanced_options.md: -------------------------------------------------------------------------------- 1 | # warf advanced options 2 | 3 | When using the `target` and `continuously` subcommands, you will have access to a bench of additionnal options. 4 | 5 | ``` 6 | $ ./warf target --help 7 | USAGE: 8 | warf target [OPTIONS] 9 | 10 | FLAGS: 11 | -h, --help Prints help information 12 | -V, --version Prints version information 13 | 14 | OPTIONS: 15 | -d, --dict Set dictionary file 16 | -f, --fuzzer Which fuzzer to run [default: Honggfuzz] [possible values: Afl, Honggfuzz, 17 | Libfuzzer] 18 | --sanitizer Set a compilation Sanitizer (advanced) [possible values: Address, Leak, Memory, 19 | Thread] 20 | -s, --seed Set seed 21 | -n, --thread Set number of thread (only for hfuzz) 22 | -t, --timeout Set timeout 23 | 24 | ARGS: 25 | Which target to run 26 | ``` 27 | 28 | ## dict (only for `target`) 29 | 30 | Allow you to provide dictionaries with input language keywords or other interesting byte sequences. More information about libfuzzer dictionary format [here](http://llvm.org/docs/LibFuzzer.html#dictionaries) 31 | 32 | Example: 33 | ``` sh 34 | $ ./warf target wast_parser -d dictionary/wast.dict 35 | ``` 36 | 37 | ## fuzzer 38 | 39 | Allow you to change which fuzzing engines will be used. The default/recommended one is honggfuzz because it's supporting all the features (especially multithreading) 40 | 41 | Example: 42 | ``` sh 43 | $ ./warf target wast_parser -f Libfuzzer 44 | ``` 45 | 46 | ## sanitizer 47 | 48 | Allow you to compile your targets with sanitizer. Sanitizer help finding bugs but slowdown your fuzzing speed. More information about sanitizer [here](https://github.com/google/sanitizers) 49 | 50 | Example: 51 | ``` sh 52 | $ ./warf target wast_parser --sanitizer address 53 | ``` 54 | 55 | ## seed 56 | 57 | Allow you to make fuzzing deterministic and reproductible. 58 | 59 | Example: 60 | ``` sh 61 | $ ./warf target wast_parser -s 12345 62 | ``` 63 | 64 | ## thread 65 | 66 | Allow you to activate multithreading and run multiple fuzzing process at the same time. By default, honggfuzz will do it using your number of core divide by 2. 67 | 68 | Example: 69 | ``` sh 70 | $ ./warf target wast_parser -n 3 # use 3 cores 71 | ``` 72 | 73 | 74 | ## timeout 75 | 76 | Allow you to limit the amount of time per fuzzing sessions. This option is useful if you want to fuzz multiple targets with a limited time for each. 77 | 78 | Example: 79 | ``` sh 80 | $ ./warf continuously -t 3600 # seconds i.e. 1 hour 81 | ``` 82 | 83 | 84 | # Other notes 85 | 86 | 87 | ## fuzzers environment variables 88 | 89 | It's possible to provide extra flags and environment variables to fuzzing engines (honggfuzz, afl++, libfuzzer). 90 | 91 | - honggfuzz-rs [here](https://github.com/rust-fuzz/honggfuzz-rs#environment-variables) 92 | - afl-rs [here](https://rust-fuzz.github.io/book/afl/tutorial.html) 93 | - libfuzzer (cargo-fuzz) - [here](https://github.com/rust-fuzz/cargo-fuzz#usage) 94 | 95 | 96 | ## afl-rs 97 | 98 | NOTES FOR AFL: 99 | 100 | ``` sh 101 | # You need to execute the following commands to get afl running properly 102 | echo core >/proc/sys/kernel/core_pattern 103 | # sudo su -c "echo core >/proc/sys/kernel/core_pattern" 104 | cd /sys/devices/system/cpu ; echo performance | tee cpu*/cpufreq/scaling_governor 105 | # sudo su -c "cd /sys/devices/system/cpu; echo performance | tee cpu*/cpufreq/scaling_governor" 106 | ``` 107 | 108 | -------------------------------------------------------------------------------- /docs/Internals.md: -------------------------------------------------------------------------------- 1 | # Global functionnement 2 | 3 | This tool dynamicaly create fuzzing harnesses depending of the specified fuzzing engine (honggfuzz, libfuzzer, afl). 4 | In short, when warf is executed, it will copy a fuzzing or debug template, replace some code inside to specify the fuzzing target library and finally run the fuzzer. 5 | 6 | If you are looking to add new targets, take a look at [how_to_add_new_fuzz_target.md](how_to_add_new_fuzz_target.md). 7 | 8 | # Architecture of the project 9 | 10 | ``` sh 11 | $ tree -L 1 12 | . 13 | ├── Cargo.lock 14 | ├── Cargo.toml 15 | ├── debug # debugging subcommand template 16 | ├── dictionary # fuzzing dictionnaries 17 | ├── Dockerfile # Docker file 18 | ├── execute_all # execute-all subcommand template 19 | ├── fuzzers # fuzzing engines templates 20 | ├── Makefile 21 | ├── src # source code of warf 22 | ├── targets # fuzzing targets source code 23 | ├── warf 24 | └── workspace # workspace shared between host and docker VM, fuzzing templates/inputs/logs/crashes are there. 25 | ``` 26 | 27 | # Templates 28 | 29 | Imagine, you are running the following command: `./warf target wasmparser_parser --fuzzer Honggfuzz` 30 | 31 | warf will do the following actions internally: 32 | - Copy `warf/fuzzers/rust-honggfuzz` folder inside the `workspace` 33 | - Copy the Honggfuzz fuzzing template `template.rs` into a new one like `workspace/hfuzz/src/bin/wasmparser_parser.rs` 34 | - Replace `###TARGET###` inside this template by the name of the target we choose (`fuzz_wasmparser_parser`) 35 | - Compile the fuzzing harness and run honggfuzz. 36 | 37 | # Fuzzing engines 38 | 39 | Warf support 3 different Rust fuzzing engines: 40 | - honggfuzz-rs 41 | - cargo-fuzz (libfuzzer) 42 | - afl.rs (AFL++) 43 | 44 | ## honggfuzz-rs 45 | 46 | *Honggfuzz is security oriented, feedback-driven, evolutionary, easy-to-use fuzzer with interesting analysis options* - [source](https://github.com/google/honggfuzz) 47 | 48 | Honggfuzz for Rust is available here: [honggfuzz-rs](https://github.com/rust-fuzz/honggfuzz-rs) / [Documentation](https://docs.rs/honggfuzz/0.5.45/honggfuzz/) and can be used with: 49 | - Rust: stable, beta, nightly. 50 | - Sanitizer: none, address, thread, leak. 51 | 52 | Full compatibility list [here](https://github.com/rust-fuzz/honggfuzz-rs#compatibility) 53 | 54 | ## cargo-fuzz (libfuzzer) 55 | 56 | Command-line wrapper for using libFuzzer. Easy to use, no need to recompile LLVM! 57 | 58 | Cargo-fuzz repository: [cargo-fuzz](https://github.com/rust-fuzz/cargo-fuzz). 59 | 60 | `cargo-fuzz` is documented in the [Rust Fuzz Book](https://rust-fuzz.github.io/book/cargo-fuzz.html). 61 | 62 | ## afl.rs 63 | 64 | American fuzzy lop (AFL) is a popular, effective, and modern fuzz testing tool. `afl.rs` allows one to run AFL on code written in the Rust programming language. 65 | 66 | `afl-rs` can be found [here](https://github.com/rust-fuzz/afl.rs) and some documention are in the [Rust Fuzz Book](https://rust-fuzz.github.io/book/afl.html). 67 | 68 | # Fuzzing techniques 69 | 70 | All previous fuzzing engines used those differents fuzzing techniques to find bugs: 71 | - Coverage-guided fuzzing: Target if compiled with some instrumentation piece of code used to monitor if some new code path has been reached during fuzzing session. 72 | - Mutation-based fuzzing: Input corpora is used and mutated/modified (using various algorithm) before being provided to the target. 73 | - Grammar-based fuzzing: Fuzzing dictionnaries will help the fuzzing engines to generate valid mutated samples. 74 | - Differential fuzzing: Result of different fuzzing targets are compared in order to find logic bugs (like improper validation or rejection of an input module) 75 | -------------------------------------------------------------------------------- /warf/src/fuzzers.rs: -------------------------------------------------------------------------------- 1 | use failure::{Error, ResultExt}; 2 | use std::fs; 3 | use std::io::Write; 4 | use std::path::PathBuf; 5 | use structopt::StructOpt; 6 | 7 | use crate::targets::Targets; 8 | #[derive(Fail, Debug)] 9 | #[fail(display = "[WARF] Fuzzer quit")] 10 | pub struct FuzzerQuit; 11 | 12 | arg_enum! { 13 | #[derive(StructOpt, Debug, Clone, Copy, PartialEq, Eq)] 14 | pub enum Fuzzer { 15 | Afl, 16 | Honggfuzz, 17 | Libfuzzer 18 | } 19 | } 20 | 21 | arg_enum! { 22 | /// All the Sanitizers currently available 23 | /// 24 | /// NOTES: https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/sanitizer.html 25 | #[derive(StructOpt, Debug, Clone, Copy, PartialEq, Eq)] 26 | pub enum Sanitizer { 27 | Address, 28 | Leak, 29 | Memory, 30 | Thread, 31 | } 32 | } 33 | 34 | impl Sanitizer { 35 | /// Sanitizer names used for RUSTFLAGS env variable. 36 | pub fn name(&self) -> String { 37 | match &self { 38 | Sanitizer::Address => "address".to_string(), 39 | Sanitizer::Leak => "leak".to_string(), 40 | Sanitizer::Memory => "memory".to_string(), 41 | Sanitizer::Thread => "thread".to_string(), 42 | } 43 | } 44 | } 45 | 46 | /// Configuration structure common for all fuzzers 47 | #[derive(Debug, Default, Clone)] 48 | pub struct FuzzerConfig { 49 | // Fuzzer timeout 50 | pub timeout: Option, 51 | // Number of fuzzing thread 52 | pub thread: Option, 53 | // Sanitizer 54 | pub sanitizer: Option, 55 | // Seed 56 | pub seed: Option, 57 | // Dictionary 58 | pub dict: Option, 59 | } 60 | 61 | /// Write the fuzzing target 62 | /// 63 | /// Copy the fuzzer/template.rs 64 | /// Replace ###TARGET### by the target 65 | pub fn write_fuzzer_target( 66 | fuzzer_dir: &PathBuf, 67 | fuzzer_workdir: &PathBuf, 68 | target: Targets, 69 | ) -> Result<(), Error> { 70 | // Get the template for this target 71 | let template_path = fuzzer_dir.join(target.template()); 72 | // Read this template file 73 | let template = fs::read_to_string(&template_path).context(format!( 74 | "error reading template file {}", 75 | template_path.display() 76 | ))?; 77 | 78 | // Target folder is different depending of the language 79 | let target_dir: PathBuf = match target.language().as_str() { 80 | "rust" => fuzzer_workdir.join("src").join("bin"), 81 | _ => bail!("target_dir for this language not defined"), 82 | }; 83 | 84 | // Try to create target directory 85 | fs::create_dir_all(&target_dir).context(format!( 86 | "error creating fuzz target dir {}", 87 | target_dir.display() 88 | ))?; 89 | 90 | // Check which file extension to use 91 | let ext: &str = match target.language().as_str() { 92 | "rust" => "rs", 93 | _ => bail!("ext for this language not defined"), 94 | }; 95 | 96 | let path = target_dir.join(&format!("{}.{}", target.name(), ext)); 97 | 98 | // Create the target harness file 99 | let mut file = fs::OpenOptions::new() 100 | .write(true) 101 | .create(true) 102 | .truncate(true) 103 | .open(&path) 104 | .context(format!( 105 | "error writing fuzz target binary {}", 106 | path.display() 107 | ))?; 108 | 109 | // Replace this pattern in the template by the target name 110 | let source = template.replace("###TARGET###", &target.name()); 111 | // Write in the file 112 | file.write_all(source.as_bytes())?; 113 | Ok(()) 114 | } 115 | -------------------------------------------------------------------------------- /warf/targets/src/wasmtime.rs: -------------------------------------------------------------------------------- 1 | /*********************************************** 2 | WASMTIME: 3 | - https://github.com/bytecodealliance/wasmtime 4 | ***********************************************/ 5 | 6 | use wasmtime::{Config, Engine, Instance, Module, Store, Strategy}; 7 | 8 | /// Fuzzing `wasmtime::validate` with default Store/Config/Engine 9 | pub fn fuzz_wasmtime_validate(data: &[u8]) -> bool { 10 | let store = Store::default(); 11 | Module::validate(&store.engine(), &data).is_ok() 12 | } 13 | 14 | /// Fuzzing `wasmtime::validate` with all the features enabled 15 | pub fn fuzz_wasmtime_validate_all_feat(data: &[u8]) -> bool { 16 | let store = match get_store_all_feat(Strategy::Cranelift) { 17 | None => return false, 18 | Some(a) => a, 19 | }; 20 | Module::validate(&store.engine(), &data).is_ok() 21 | } 22 | 23 | /// Fuzzing `wasmtime::Module` with default Store/Config/Engine 24 | /// 25 | /// NOTE: wasmtime::from_binary is also calling wasmtime::validate. 26 | pub fn fuzz_wasmtime_compile(data: &[u8]) -> bool { 27 | let store = Store::default(); 28 | Module::from_binary(&store.engine(), &data).is_ok() 29 | } 30 | 31 | /// Return a Store created with the given Strategy and with 32 | /// all the features enabled 33 | fn get_store_all_feat(strategy: Strategy) -> Option { 34 | // Create new compilation config 35 | let mut config = Config::new(); 36 | // Select Cranelift as compiler 37 | if config.strategy(strategy).is_err() { 38 | return None; 39 | }; 40 | 41 | // Activate all wasm features in Config 42 | // https://docs.rs/wasmtime/0.15.0/wasmtime/struct.Config.html 43 | config 44 | .debug_info(true) 45 | .wasm_threads(true) 46 | .wasm_reference_types(true) 47 | .wasm_simd(true) 48 | .wasm_bulk_memory(true) 49 | .wasm_multi_value(true); 50 | let store = Store::new(&Engine::new(&config)); 51 | Some(store) 52 | } 53 | 54 | /// Fuzzing `wasmtime::Module` with all wasm features and `Cranelift` backend. 55 | pub fn fuzz_wasmtime_compile_all_cranelift(data: &[u8]) -> bool { 56 | let store = match get_store_all_feat(Strategy::Cranelift) { 57 | None => return false, 58 | Some(a) => a, 59 | }; 60 | Module::from_binary(&store.engine(), &data).is_ok() 61 | } 62 | 63 | /// Fuzzing `wasmtime::Module` with all wasm features and `Lightbeam` backend. 64 | pub fn fuzz_wasmtime_compile_all_lightbeam(data: &[u8]) -> bool { 65 | let store = match get_store_all_feat(Strategy::Lightbeam) { 66 | None => return false, 67 | Some(a) => a, 68 | }; 69 | Module::from_binary(&store.engine(), &data).is_ok() 70 | } 71 | 72 | /// Fuzzing `wasmtime::Instance` with all wasm features and `Cranelift` backend. 73 | pub fn fuzz_wasmtime_instantiate_all_cranelift(data: &[u8]) -> bool { 74 | let store = match get_store_all_feat(Strategy::Cranelift) { 75 | None => return false, 76 | Some(a) => a, 77 | }; 78 | // Create a Module 79 | let module = match Module::from_binary(&store.engine(), &data) { 80 | Ok(a) => a, 81 | _ => return false, 82 | }; 83 | Instance::new(&store, &module, &[]).is_ok() 84 | // TODO(RM4) - check parameter Instance 85 | // TODO(RM4) - Execute function of the module 86 | } 87 | 88 | /// Fuzzing `wasmtime::Instance` with all wasm features and `Lightbeam` backend. 89 | pub fn fuzz_wasmtime_instantiate_all_lightbeam(data: &[u8]) -> bool { 90 | let store = match get_store_all_feat(Strategy::Lightbeam) { 91 | None => return false, 92 | Some(a) => a, 93 | }; 94 | // Create a Module 95 | let module = match Module::from_binary(&store.engine(), &data) { 96 | Ok(a) => a, 97 | _ => return false, 98 | }; 99 | Instance::new(&store, &module, &[]).is_ok() 100 | 101 | // TODO(RM4) - check parameter Instance 102 | // TODO(RM4) - Execute function of the module 103 | } 104 | -------------------------------------------------------------------------------- /warf/src/exec_all.rs: -------------------------------------------------------------------------------- 1 | extern crate clap; 2 | extern crate failure; 3 | extern crate fs_extra; 4 | extern crate regex; 5 | extern crate structopt; 6 | 7 | use crate::fuzzers::FuzzerQuit; 8 | use std::fs; 9 | use std::path::PathBuf; 10 | use std::process::Command; 11 | 12 | use failure::{Error, ResultExt}; 13 | 14 | use std::io::Write; 15 | 16 | use crate::env::{root_dir, workspace_dir}; 17 | use crate::targets::{get_targets, prepare_targets_workspace}; 18 | 19 | fn prepare_exec_all_workspace(out_dir: &str) -> Result<(), Error> { 20 | let debug_init_dir = root_dir()?.join("execute_all"); 21 | let dir = root_dir()?.join("workspace"); 22 | 23 | let debug_dir = dir.join(out_dir); 24 | fs::create_dir_all(&debug_dir) 25 | .context(format!("unable to create {} dir", debug_dir.display()))?; 26 | 27 | let src_dir = debug_dir.join("src"); 28 | fs::create_dir_all(&src_dir).context(format!("unable to create {} dir", src_dir.display()))?; 29 | 30 | fs::copy( 31 | debug_init_dir.join("Cargo.toml"), 32 | debug_dir.join("Cargo.toml"), 33 | )?; 34 | fs::copy( 35 | debug_init_dir.join("src").join("lib.rs"), 36 | src_dir.join("lib.rs"), 37 | )?; 38 | Ok(()) 39 | } 40 | 41 | pub fn run_exec_all(wasm: String, benchmark: bool) -> Result<(), Error> { 42 | let debug_dir = root_dir()?.join("workspace").join("execute_all"); 43 | 44 | prepare_targets_workspace()?; 45 | prepare_exec_all_workspace("execute_all")?; 46 | 47 | write_exec_all_target(&debug_dir, benchmark)?; 48 | 49 | let debug_bin = Command::new("cargo") 50 | .args(&["build", "--release", "--bin", "exec_all"]) 51 | .args(&["--out-dir=..", "-Z", "unstable-options"]) // copy exec_all binary in workspace folder 52 | .current_dir(&debug_dir) 53 | .spawn() 54 | .context("execute_all")? 55 | .wait() 56 | .context("execute_all")?; 57 | 58 | if !debug_bin.success() { 59 | Err(FuzzerQuit)?; 60 | } 61 | println!( 62 | "[WARF] execute_all compiled here: {:#?}/exec_all", 63 | workspace_dir()? 64 | ); 65 | 66 | // Execute the exec_all 67 | let debug_bin = Command::new(workspace_dir()?.join("exec_all")) 68 | .arg(wasm) 69 | .current_dir(root_dir()?) 70 | .spawn() 71 | .context("exec_all")? 72 | .wait() 73 | .context("exec_all")?; 74 | 75 | if !debug_bin.success() { 76 | Err(FuzzerQuit)?; 77 | } 78 | 79 | Ok(()) 80 | } 81 | 82 | fn write_exec_all_target(debug_dir: &PathBuf, benchmark: bool) -> Result<(), Error> { 83 | // TODO - make it cleaner 84 | let template_path = root_dir()?.join("execute_all").join("exec_all_template.rs"); 85 | let template = fs::read_to_string(&template_path).context(format!( 86 | "error reading execute_all template file {}", 87 | template_path.display() 88 | ))?; 89 | 90 | let target_dir = debug_dir.join("src").join("bin"); 91 | fs::create_dir_all(&target_dir).context(format!( 92 | "error creating execute_all target dir {}", 93 | target_dir.display() 94 | ))?; 95 | let path = target_dir.join("exec_all.rs"); 96 | 97 | let mut file = fs::OpenOptions::new() 98 | .write(true) 99 | .create(true) 100 | .truncate(true) 101 | .open(&path) 102 | .context(format!( 103 | "error writing execute_all target binary {}", 104 | path.display() 105 | ))?; 106 | 107 | // TODO 108 | let mut targets = String::new(); 109 | for target in get_targets() { 110 | if benchmark { 111 | targets.push_str(" let it = Instant::now();\n"); 112 | } 113 | targets.push_str(&format!(" let res = debug_{}(&data);\n", target)); 114 | targets.push_str(&format!(" is_ok(\"{}\".to_string(), res);\n\n", target)); 115 | if benchmark { 116 | targets.push_str(" log_benchmark(it);\n"); 117 | } 118 | } 119 | let source = template.replace("###TARGETS###", &targets); 120 | file.write_all(source.as_bytes())?; 121 | Ok(()) 122 | } 123 | -------------------------------------------------------------------------------- /warf/src/debug.rs: -------------------------------------------------------------------------------- 1 | use crate::strum::IntoEnumIterator; 2 | 3 | use failure::{Error, ResultExt}; 4 | use std::fs; 5 | use std::path::PathBuf; 6 | use std::process::Command; 7 | 8 | use crate::env::root_dir; 9 | use crate::fuzzers::FuzzerQuit; 10 | 11 | use crate::targets::{get_targets, prepare_targets_workspace, Targets}; 12 | use crate::utils::did_you_mean; 13 | 14 | // TODO - simplify 15 | pub fn prepare_debug_workspace(out_dir: &str) -> Result<(), Error> { 16 | let debug_init_dir = root_dir()?.join("debug"); 17 | let dir = root_dir()?.join("workspace"); 18 | 19 | let debug_dir = dir.join(out_dir); 20 | fs::create_dir_all(&debug_dir) 21 | .context(format!("unable to create {} dir", debug_dir.display()))?; 22 | 23 | let src_dir = debug_dir.join("src"); 24 | fs::create_dir_all(&src_dir).context(format!("unable to create {} dir", src_dir.display()))?; 25 | 26 | fs::copy( 27 | debug_init_dir.join("Cargo.toml"), 28 | debug_dir.join("Cargo.toml"), 29 | )?; 30 | fs::copy( 31 | debug_init_dir.join("src").join("lib.rs"), 32 | src_dir.join("lib.rs"), 33 | )?; 34 | Ok(()) 35 | } 36 | 37 | // TODO - move part of this function to main.rs 38 | // TODO - to specific to Rust 39 | pub fn run_debug(target: String) -> Result<(), Error> { 40 | let target = match Targets::iter().find(|x| x.name() == target) { 41 | None => bail!( 42 | "Don't know target `{}`. {}", 43 | target, 44 | if let Some(alt) = did_you_mean(&target, &get_targets()) { 45 | format!("Did you mean `{}`?", alt) 46 | } else { 47 | "".into() 48 | } 49 | ), 50 | Some(t) => t, 51 | }; 52 | 53 | let debug_dir = root_dir()?.join("workspace").join("debug"); 54 | 55 | prepare_targets_workspace()?; 56 | prepare_debug_workspace("debug")?; 57 | 58 | write_debug_target(debug_dir.clone(), target)?; 59 | 60 | let debug_bin = Command::new("cargo") 61 | .args(&[ 62 | //"+nightly", 63 | "build", 64 | "--bin", 65 | &format!("debug_{}", target.name()), 66 | ]) 67 | .current_dir(&debug_dir) 68 | .spawn() 69 | .context(format!("error starting {}", target.name()))? 70 | .wait() 71 | .context(format!("error while waiting for {}", target.name()))?; 72 | 73 | if !debug_bin.success() { 74 | return Err(FuzzerQuit.into()); 75 | } 76 | println!( 77 | "[WARF] Debug: {} compiled", 78 | &format!("debug_{}", target.name()) 79 | ); 80 | Ok(()) 81 | } 82 | 83 | pub fn write_debug_target(debug_dir: PathBuf, target: Targets) -> Result<(), Error> { 84 | use std::io::Write; 85 | 86 | // TODO - make it cleaner 87 | let template_path = root_dir()? 88 | .join("debug") 89 | .join(format!("debug_{}", target.template())); 90 | let template = fs::read_to_string(&template_path).context(format!( 91 | "error reading debug template file {}", 92 | template_path.display() 93 | ))?; 94 | 95 | let target_dir: PathBuf = match target.language().as_str() { 96 | "rust" => debug_dir.join("src").join("bin"), 97 | _ => bail!("target_dir for this language not defined"), 98 | }; 99 | 100 | fs::create_dir_all(&target_dir).context(format!( 101 | "error creating debug target dir {}", 102 | target_dir.display() 103 | ))?; 104 | 105 | let ext: &str = match target.language().as_str() { 106 | "rust" => "rs", 107 | _ => bail!("ext for this language not defined"), 108 | }; 109 | let path = target_dir.join(&format!("debug_{}.{}", target.name(), ext)); 110 | 111 | let mut file = fs::OpenOptions::new() 112 | .write(true) 113 | .create(true) 114 | .truncate(true) 115 | .open(&path) 116 | .context(format!( 117 | "error writing debug target binary {}", 118 | path.display() 119 | ))?; 120 | 121 | let source = template.replace("###TARGET###", &target.name()); 122 | file.write_all(source.as_bytes())?; 123 | Ok(()) 124 | } 125 | -------------------------------------------------------------------------------- /.github/workflows/rust.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | # Check code style quickly by running `rustfmt` over all code 11 | rustfmt: 12 | name: Check Rust fmt 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/checkout@v2 16 | - name: Install latest nightly 17 | uses: actions-rs/toolchain@v1 18 | with: 19 | toolchain: nightly 20 | override: true 21 | components: rustfmt 22 | 23 | - name: Run cargo fmt 24 | run: cd warf && make check-fmt 25 | 26 | # Build only warf tool 27 | build: 28 | name: Building warf cli 29 | runs-on: ubuntu-latest 30 | steps: 31 | - uses: actions/checkout@v2 32 | - name: Install latest nightly 33 | uses: actions-rs/toolchain@v1 34 | with: 35 | toolchain: nightly 36 | override: true 37 | 38 | - name: Build 39 | run: cd warf && make build 40 | 41 | # Try to compile the dockerfile 42 | build-docker: 43 | name: Building docker 44 | runs-on: ubuntu-latest 45 | steps: 46 | - uses: actions/checkout@v2 47 | - name: Install latest nightly 48 | uses: actions-rs/toolchain@v1 49 | with: 50 | toolchain: nightly 51 | override: true 52 | 53 | - name: Build Docker 54 | run: cd warf && make docker 55 | 56 | # Test libfuzzer 57 | test-libfuzzer: 58 | name: test libfuzzer 59 | runs-on: ubuntu-latest 60 | steps: 61 | - uses: actions/checkout@v2 62 | - name: Install latest nightly 63 | uses: actions-rs/toolchain@v1 64 | with: 65 | toolchain: nightly 66 | override: true 67 | 68 | - name: Install cargo-fuzz 69 | run: cargo +nightly install --force cargo-fuzz 70 | - name: Test libfuzzer 71 | run: cd warf && make test-libfuzzer 72 | 73 | # Test honggfuzz 74 | test-honggfuzz: 75 | name: test honggfuzz 76 | runs-on: ubuntu-latest 77 | steps: 78 | - uses: actions/checkout@v2 79 | - name: Install latest nightly 80 | uses: actions-rs/toolchain@v1 81 | with: 82 | toolchain: nightly 83 | override: true 84 | 85 | - name: Install honggfuzz dependencies 86 | run: | 87 | sudo apt-get update 88 | sudo apt install -y build-essential binutils-dev libunwind-dev libblocksruntime-dev 89 | - name: Install honggfuzz 90 | run: cargo +nightly install --force honggfuzz 91 | - name: Test honggfuzz 92 | run: cd warf && make test-honggfuzz 93 | 94 | # Test afl 95 | test-afl: 96 | name: test afl 97 | runs-on: ubuntu-latest 98 | steps: 99 | - uses: actions/checkout@v2 100 | - name: Install latest nightly 101 | uses: actions-rs/toolchain@v1 102 | with: 103 | toolchain: nightly 104 | override: true 105 | - name: Install afl dependencies 106 | run: | 107 | sudo apt-get update 108 | sudo apt install -y llvm build-essential libtool-bin python3 cmake automake bison libglib2.0-dev libpixman-1-dev clang python-setuptools 109 | - name: Install afl 110 | run: cargo +nightly install --force afl 111 | - name: Test afl 112 | run: cd warf && make test-afl 113 | 114 | # Test exec_all 115 | test-exec-all: 116 | name: test exec_all 117 | runs-on: ubuntu-latest 118 | steps: 119 | - uses: actions/checkout@v2 120 | - name: Install latest nightly 121 | uses: actions-rs/toolchain@v1 122 | with: 123 | toolchain: nightly 124 | override: true 125 | - name: Test exec_all 126 | run: cd warf && make test 127 | 128 | # Test benchmark 129 | test-benchmark: 130 | name: test benchmark 131 | runs-on: ubuntu-latest 132 | steps: 133 | - uses: actions/checkout@v2 134 | - name: Install latest nightly 135 | uses: actions-rs/toolchain@v1 136 | with: 137 | toolchain: nightly 138 | override: true 139 | - name: Test benchmark 140 | run: cd warf && make test-bench 141 | -------------------------------------------------------------------------------- /warf/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: default update check-fmt help build docker corpora fmt clean clean-all test test-bench test-debug test-libfuzzer test-honggfuzz test-afl test-all 2 | 3 | # 4 | # User utils 5 | # 6 | 7 | default: build 8 | 9 | help: 10 | @echo 'Management commands for warf' 11 | @echo 12 | @echo 'Usage:' 13 | @echo ' make build Compile the project locally.' 14 | @echo ' make docker Build a docker image for this project.' 15 | @echo ' make corpora TODO' 16 | @echo 17 | @echo ' make fmt Run Rust fmt.' 18 | @echo ' make clean Clean only warf binary.' 19 | @echo ' make clean-all Clean all (warf && compiled fuzz target harnesses).' 20 | @echo 21 | @echo ' make test Simple test to check warf and execute_all is working.' 22 | @echo ' make test-bench Simple benchmark using execute_all.' 23 | @echo ' make test-debug Test running a simple wasm to a debugging tool.' 24 | @echo ' make test-{libfuzzer, honggfuzz, afl} Test one fuzzing hardness over choosen fuzzer.' 25 | @echo ' make test-continuously-{libfuzzer, hfuzz, afl} Test all fuzzing hardness over choosen fuzzer.' 26 | @echo ' make test-all Test all fuzzing hardness over all fuzzers.' 27 | @echo 28 | 29 | # Compile the project locally 30 | build: 31 | cargo +nightly build --release --out-dir=. -Z unstable-options 32 | 33 | # Build the docker 34 | # NOTE: `make docker CACHE=--no-cache` to force docker update/build everything again 35 | docker: 36 | DOCKER_BUILDKIT=1 docker build . -t warf $(CACHE) 37 | @echo 'USAGE: docker run -it -v `pwd`/workspace:/warf/workspace warf list' 38 | 39 | # Create an initial corpora of wasm modules 40 | corpora: 41 | echo "TODO" 42 | 43 | # Run Rust fmt to make code cleaner 44 | fmt: 45 | cargo fmt --all 46 | 47 | # Clean only warf target 48 | clean: 49 | rm -rf target/ 50 | rm -rf ./warf 51 | 52 | # Clean all (warf && compiled fuzz target harnesses). 53 | clean-all: clean 54 | rm -rf workspace/debug/target 55 | rm -rf workspace/execute_all/target 56 | rm -rf workspace/afl/target/ 57 | rm -rf workspace/hfuzz/hfuzz_target/ 58 | rm -rf workspace/libfuzzer/fuzz/target/ 59 | 60 | # update to latest cargo package version 61 | update: 62 | cargo update 63 | cd targets && cargo update 64 | cd execute_all && cargo update 65 | cd debug && cargo update 66 | (cd workspace/afl && cargo update) || true 67 | (cd workspace/hfuzz && cargo update) || true 68 | (cd workspace/libfuzzer && cargo update) || true 69 | 70 | # 71 | # Testing utils 72 | # warf cli sub-commands 73 | # 74 | 75 | # Simple test using docker. 76 | docker-test: docker 77 | docker run -it -v `pwd`/workspace:/warf/workspace warf list 78 | 79 | # Simple test with wasm using docker. 80 | docker-test-all: docker 81 | docker run -it -v `pwd`/workspace:/warf/workspace warf execute-all workspace/corpora/wasm/fib.wasm 82 | 83 | # Simple test using execute_all 84 | test: build 85 | ./warf execute-all workspace/corpora/wasm/fib.wasm 86 | 87 | # Simple benchmark test using execute_all 88 | test-bench: build 89 | ./warf benchmark-all workspace/corpora/wasm/fib.wasm 90 | 91 | # Compile one debug tool and run a simple wasm to it 92 | test-debug: build 93 | ./warf debug wasmparser_parser 94 | ./workspace/debug/target/debug/debug_wasmparser_parser workspace/corpora/wasm/fib.wasm 95 | 96 | # Run one fuzzing hardness over libfuzzer during 2s 97 | test-libfuzzer: build 98 | ./warf target wasmparser_parser -t 2 -s 1234 --fuzzer libfuzzer 99 | 100 | # Run fuzzing hardness over honggfuzz during 2s 101 | test-honggfuzz: build 102 | ./warf target wasmparser_parser -t 2 -s 1234 --fuzzer honggfuzz 103 | 104 | # Run fuzzing hardness over afl during 2s 105 | test-afl: build 106 | AFL_SKIP_CPUFREQ=1 \ 107 | AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1 \ 108 | ./warf target wasmparser_parser -t 2 -s 1234 --fuzzer afl 109 | 110 | 111 | # Run all fuzzing hardness over libfuzzer 112 | test-continuously-libfuzzer: build 113 | ./warf continuously -t 2 -s 1234 --fuzzer libfuzzer 114 | 115 | # Run all fuzzing hardness over honggfuzz 116 | test-continuously-honggfuzz: build 117 | ./warf continuously -t 2 -s 1234 --fuzzer honggfuzz 118 | 119 | # Run all fuzzing hardness over afl 120 | test-continuously-afl: build 121 | AFL_SKIP_CPUFREQ=1 \ 122 | AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1 \ 123 | ./warf continuously -t 2 -s 1234 --fuzzer afl 124 | 125 | # Run all tests 126 | # (Really) Heavy test 127 | test-all: test test-bench test-debug test-libfuzzer test-honggfuzz test-afl 128 | 129 | # 130 | # Developer utils 131 | # 132 | 133 | # Update rust fuzzers (afl, honggfuzz and libfuzzer) to last version 134 | # TODO: move to an install/update script? 135 | update-fuzzer: 136 | cargo +nightly install --force honggfuzz 137 | cargo +nightly install --force cargo-fuzz 138 | cargo +nightly install --force afl 139 | 140 | # 141 | # CI utils 142 | # 143 | 144 | # Check code style quickly by running `rustfmt` over all code 145 | check-fmt: 146 | cargo fmt --all -- --check 147 | 148 | build-exec-all: build 149 | ./warf execute-all 150 | -------------------------------------------------------------------------------- /docs/how_to_analyze_a_crash.md: -------------------------------------------------------------------------------- 1 | # How to analyze a crash 2 | 3 | In this example, I will explain how to analyze a crash triggered by the fuzzer for `wasmer_compile_clif` target. 4 | 5 | # Where is my crash? 6 | 7 | Crash are detected and annonced immediately by the fuzzer (like in the following `honggfuzz` interface): 8 | ``` sh 9 | ------------------------[ 0 days 00 hrs 13 mins 37 secs ]---------------------- 10 | Iterations : 265,459 [265.46k] 11 | Mode [3/3] : Feedback Driven Mode 12 | Target : hfuzz_target/x86_64-unknown-linux-gnu/release/wasmer_compile_clif 13 | Threads : 4, CPUs: 8, CPU%: 569% [71%/CPU] 14 | Speed : 58,231/sec [avg: 53,091] 15 | ==> Crashes : 21 [unique: 1, blacklist: 0, verified: 0] 16 | Timeouts : 0 [10 sec] 17 | Corpus Size : 1,117, max: 8,192 bytes, init: 1,218 files 18 | Cov Update : 0 days 00 hrs 00 mins 00 secs ago 19 | Coverage : edge: 9,536/185,317 [5%] pc: 51 cmp: 167,998 20 | ---------------------------------- [ LOGS ] ------------------/ honggfuzz 2.0 /- 21 | ``` 22 | 23 | Crash has been stored by honggfuzz inside workspace/hfuzz/hfuzz_workspace/: 24 | ``` sh 25 | $ ls workspace/hfuzz/hfuzz_workspace/wasmer_compile_clif 26 | 27 | HONGGFUZZ.REPORT.TXT 28 | input 29 | 'SIGABRT.PC.7ffff71dfe97.STACK.1b941138b2.CODE.-6.ADDR.0.INSTR.mov____0x108(%rsp),%rcx.fuzz' 30 | ``` 31 | Copy this file in `warf` and rename it to `crash_to_analyze.wasm`, will be easier for next part ;) 32 | 33 | 34 | # Compile your target with warf debug 35 | 36 | ``` sh 37 | $ ./warf debug wasmer_compile_clif 38 | 39 | [...] 40 | [WARF] Debug: debug_wasmer_compile_clif compiled 41 | ``` 42 | Your debugging tool is now available here: `./workspace/debug/target/debug/debug_wasmer_compile_clif` 43 | 44 | # Run the debug tool with the crash 45 | 46 | ``` sh 47 | $ ./debug_wasmer_compile_clif crash_to_analyze.wasm 48 | 49 | Start debugging of wasmer_compile_clif 50 | file_to_process: "crash_to_analyze.wasm" 51 | thread 'main' panicked at 'index out of bounds: the len is 0 but the index is 0', /rustc/85976442558bf2d09cec3aa49c9c9ba86fb15c1f/src/libcore/slice/mod.rs:2791:10 52 | note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace. 53 | ``` 54 | We can see here that it is a legitimate/valid bug triggering an index out of bounds panic in `wasmer`. 55 | 56 | # Deeper analysis / BACKTRACE 57 | 58 | You can use the `RUST_BACKTRACE` environment variable to get more information about the root cause of this bug: 59 | ``` sh 60 | $ RUST_BACKTRACE=1 ./debug_wasmer_compile_clif crash_to_analyze.wasm 61 | 62 | Start debugging of wasmer_compile_clif 63 | file_to_process: "crash_to_analyze.wasm" 64 | thread 'main' panicked at 'index out of bounds: the len is 0 but the index is 0', /rustc/85976442558bf2d09cec3aa49c9c9ba86fb15c1f/src/libcore/slice/mod.rs:2791:10 65 | stack backtrace: 66 | 0: backtrace::backtrace::libunwind::trace 67 | at /cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.40/src/backtrace/libunwind.rs:88 68 | 1: backtrace::backtrace::trace_unsynchronized 69 | at /cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.40/src/backtrace/mod.rs:66 70 | 2: std::sys_common::backtrace::_print_fmt 71 | at src/libstd/sys_common/backtrace.rs:77 72 | [...] 73 | at src/libcore/panicking.rs:85 74 | 13: core::panicking::panic_bounds_check 75 | at src/libcore/panicking.rs:63 76 | 14: >::index 77 | at /rustc/85976442558bf2d09cec3aa49c9c9ba86fb15c1f/src/libcore/slice/mod.rs:2791 78 | 15: core::slice:: for [T]>::index 79 | at /rustc/85976442558bf2d09cec3aa49c9c9ba86fb15c1f/src/libcore/slice/mod.rs:2656 80 | 16: as core::ops::index::Index>::index 81 | at /rustc/85976442558bf2d09cec3aa49c9c9ba86fb15c1f/src/liballoc/vec.rs:1882 82 | 17: as core::ops::index::Index>::index 83 | at /home/scop/.cargo/registry/src/github.com-1ecc6299db9ec823/cranelift-entity-0.59.0/src/primary.rs:162 84 | ==> 18: wasmer_clif_fork_wasm::translation_utils::blocktype_params_results 85 | ==> at /home/scop/.cargo/registry/src/github.com-1ecc6299db9ec823/wasmer-clif-fork-wasm-0.59.0/src/translation_utils.rs:194 86 | ==> 19: wasmer_clif_fork_wasm::code_translator::translate_operator 87 | ==> at /home/scop/.cargo/registry/src/github.com-1ecc6299db9ec823/wasmer-clif-fork-wasm-0.59.0/src/code_translator.rs:185 88 | 20: >::feed_event 89 | at /home/scop/.cargo/registry/src/github.com-1ecc6299db9ec823/wasmer-clif-backend-0.16.2/src/code.rs:1208 90 | 21: wasmer_runtime_core::codegen::MiddlewareChain::run 91 | at /home/scop/.cargo/registry/src/github.com-1ecc6299db9ec823/wasmer-runtime-core-0.16.2/src/codegen.rs:420 92 | 22: wasmer_runtime_core::parse::read_module 93 | at /home/scop/.cargo/registry/src/github.com-1ecc6299db9ec823/wasmer-runtime-core-0.16.2/src/parse.rs:309 94 | 23: as wasmer_runtime_core::backend::Compiler>::compile 95 | at /home/scop/.cargo/registry/src/github.com-1ecc6299db9ec823/wasmer-runtime-core-0.16.2/src/codegen.rs:314 96 | 24: wasmer_runtime_core::compile_with 97 | at /home/scop/.cargo/registry/src/github.com-1ecc6299db9ec823/wasmer-runtime-core-0.16.2/src/lib.rs:115 98 | 25: wasmer_runtime::compile 99 | at /home/scop/.cargo/registry/src/github.com-1ecc6299db9ec823/wasmer-runtime-0.16.2/src/lib.rs:244 100 | 26: fuzz_targets_common::fuzz_wasmer_compile_clif 101 | at common/src/lib.rs:30 102 | [...] 103 | at src/libstd/rt.rs:51 104 | 35: std::rt::lang_start 105 | at /rustc/85976442558bf2d09cec3aa49c9c9ba86fb15c1f/src/libstd/rt.rs:67 106 | 36: main 107 | 37: __libc_start_main 108 | 38: _start 109 | note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace. 110 | ``` 111 | 112 | Congrats, you can now report your finding to the project owner like I've done [here](https://github.com/wasmerio/wasmer/issues/1372) 113 | -------------------------------------------------------------------------------- /warf/dictionary/wast.dict: -------------------------------------------------------------------------------- 1 | # AFL dictionary for the WAST format 2 | # https://github.com/WebAssembly/wabt/blob/master/fuzz-in/wast.dict 3 | 4 | open="(" 5 | close=")" 6 | comment=";;" 7 | block_comment_open="(;" 8 | block_comment_close=";)" 9 | 10 | param_i32="(param i32)" 11 | param_i64="(param i64)" 12 | param_f32="(param f32)" 13 | param_f64="(param f64)" 14 | 15 | result_i32="(result i32)" 16 | result_i64="(result i64)" 17 | result_f32="(result f32)" 18 | result_f64="(result f64)" 19 | 20 | type_i32="i32" 21 | type_i64="i64" 22 | type_f32="f32" 23 | type_f64="f64" 24 | 25 | misc_name="$foobar" 26 | misc_int="42" 27 | misc_int_hex="0xdeadcode" 28 | misc_float="3.14159" 29 | misc_float_exp="1e100" 30 | misc_float_hex="0xcab.ba6ep4" 31 | misc_float_inf="infinity" 32 | misc_float_nan="nan:0xf00baa" 33 | misc_float_sign="-6.02e-23" 34 | 35 | op_nop="nop" 36 | op_block="block" 37 | op_if="if" 38 | op_then="then" 39 | op_else="else" 40 | op_loop="loop" 41 | op_br="br" 42 | op_br_if="br_if" 43 | op_br_table="br_table" 44 | op_call="call" 45 | op_call_indirect="call_indirect" 46 | op_drop="drop" 47 | op_end="end" 48 | op_return="return" 49 | op_get_local="get_local" 50 | op_set_local="set_local" 51 | op_tee_local="tee_local" 52 | op_get_global="get_global" 53 | op_set_global="set_global" 54 | op_i32_load="i32.load" 55 | op_i64_load="i64.load" 56 | op_f32_load="f32.load" 57 | op_f64_load="f64.load" 58 | op_i32_store="i32.store" 59 | op_i64_store="i64.store" 60 | op_f32_store="f32.store" 61 | op_f64_store="f64.store" 62 | op_i32_load8_s="i32.load8_s" 63 | op_i64_load8_s="i64.load8_s" 64 | op_i32_load8_u="i32.load8_u" 65 | op_i64_load8_u="i64.load8_u" 66 | op_i32_load16_s="i32.load16_s" 67 | op_i64_load16_s="i64.load16_s" 68 | op_i32_load16_u="i32.load16_u" 69 | op_i64_load16_u="i64.load16_u" 70 | op_i64_load32_s="i64.load32_s" 71 | op_i64_load32_u="i64.load32_u" 72 | op_i32_store8="i32.store8" 73 | op_i64_store8="i64.store8" 74 | op_i32_store16="i32.store16" 75 | op_i64_store16="i64.store16" 76 | op_i64_store32="i64.store32" 77 | op_i32_const="i32.const" 78 | op_i64_const="i64.const" 79 | op_f32_const="f32.const" 80 | op_f64_const="f64.const" 81 | op_i32_eqz="i32.eqz" 82 | op_i64_eqz="i64.eqz" 83 | op_i32_clz="i32.clz" 84 | op_i64_clz="i64.clz" 85 | op_i32_ctz="i32.ctz" 86 | op_i64_ctz="i64.ctz" 87 | op_i32_popcnt="i32.popcnt" 88 | op_i64_popcnt="i64.popcnt" 89 | op_f32_neg="f32.neg" 90 | op_f64_neg="f64.neg" 91 | op_f32_abs="f32.abs" 92 | op_f64_abs="f64.abs" 93 | op_f32_sqrt="f32.sqrt" 94 | op_f64_sqrt="f64.sqrt" 95 | op_f32_ceil="f32.ceil" 96 | op_f64_ceil="f64.ceil" 97 | op_f32_floor="f32.floor" 98 | op_f64_floor="f64.floor" 99 | op_f32_trunc="f32.trunc" 100 | op_f64_trunc="f64.trunc" 101 | op_f32_nearest="f32.nearest" 102 | op_f64_nearest="f64.nearest" 103 | op_i32_add="i32.add" 104 | op_i64_add="i64.add" 105 | op_i32_sub="i32.sub" 106 | op_i64_sub="i64.sub" 107 | op_i32_mul="i32.mul" 108 | op_i64_mul="i64.mul" 109 | op_i32_div_s="i32.div_s" 110 | op_i64_div_s="i64.div_s" 111 | op_i32_div_u="i32.div_u" 112 | op_i64_div_u="i64.div_u" 113 | op_i32_rem_s="i32.rem_s" 114 | op_i64_rem_s="i64.rem_s" 115 | op_i32_rem_u="i32.rem_u" 116 | op_i64_rem_u="i64.rem_u" 117 | op_i32_and="i32.and" 118 | op_i64_and="i64.and" 119 | op_i32_or="i32.or" 120 | op_i64_or="i64.or" 121 | op_i32_xor="i32.xor" 122 | op_i64_xor="i64.xor" 123 | op_i32_shl="i32.shl" 124 | op_i64_shl="i64.shl" 125 | op_i32_shr_s="i32.shr_s" 126 | op_i64_shr_s="i64.shr_s" 127 | op_i32_shr_u="i32.shr_u" 128 | op_i64_shr_u="i64.shr_u" 129 | op_i32_rotl="i32.rotl" 130 | op_i64_rotl="i64.rotl" 131 | op_f32_add="f32.add" 132 | op_f64_add="f64.add" 133 | op_f32_sub="f32.sub" 134 | op_f64_sub="f64.sub" 135 | op_f32_mul="f32.mul" 136 | op_f64_mul="f64.mul" 137 | op_f32_div="f32.div" 138 | op_f64_div="f64.div" 139 | op_f32_min="f32.min" 140 | op_f64_min="f64.min" 141 | op_f32_max="f32.max" 142 | op_f64_max="f64.max" 143 | op_f32_copysign="f32.copysign" 144 | op_f64_copysign="f64.copysign" 145 | op_i32_eq="i32.eq" 146 | op_i64_eq="i64.eq" 147 | op_i32_ne="i32.ne" 148 | op_i64_ne="i64.ne" 149 | op_i32_lt_s="i32.lt_s" 150 | op_i64_lt_s="i64.lt_s" 151 | op_i32_lt_u="i32.lt_u" 152 | op_i64_lt_u="i64.lt_u" 153 | op_i32_le_s="i32.le_s" 154 | op_i64_le_s="i64.le_s" 155 | op_i32_le_u="i32.le_u" 156 | op_i64_le_u="i64.le_u" 157 | op_i32_gt_s="i32.gt_s" 158 | op_i64_gt_s="i64.gt_s" 159 | op_i32_gt_u="i32.gt_u" 160 | op_i64_gt_u="i64.gt_u" 161 | op_i32_ge_s="i32.ge_s" 162 | op_i64_ge_s="i64.ge_s" 163 | op_i32_ge_u="i32.ge_u" 164 | op_i64_ge_u="i64.ge_u" 165 | op_f32_eq="f32.eq" 166 | op_f64_eq="f64.eq" 167 | op_f32_ne="f32.ne" 168 | op_f64_ne="f64.ne" 169 | op_f32_lt="f32.lt" 170 | op_f64_lt="f64.lt" 171 | op_f32_le="f32.le" 172 | op_f64_le="f64.le" 173 | op_f32_gt="f32.gt" 174 | op_f64_gt="f64.gt" 175 | op_f32_ge="f32.ge" 176 | op_f64_ge="f64.ge" 177 | op_i64_extend_s_i32="i64.extend_s/i32" 178 | op_i64_extend_u_i32="i64.extend_u/i32" 179 | op_i32_wrap_i64="i32.wrap/i64" 180 | op_i32_trunc_s_f32="i32.trunc_s/f32" 181 | op_i64_trunc_s_f32="i64.trunc_s/f32" 182 | op_i32_trunc_s_f64="i32.trunc_s/f64" 183 | op_i64_trunc_s_f64="i64.trunc_s/f64" 184 | op_i32_trunc_u_f32="i32.trunc_u/f32" 185 | op_i64_trunc_u_f32="i64.trunc_u/f32" 186 | op_i32_trunc_u_f64="i32.trunc_u/f64" 187 | op_i64_trunc_u_f64="i64.trunc_u/f64" 188 | op_f32_convert_s_i32="f32.convert_s/i32" 189 | op_f64_convert_s_i32="f64.convert_s/i32" 190 | op_f32_convert_s_i64="f32.convert_s/i64" 191 | op_f64_convert_s_i64="f64.convert_s/i64" 192 | op_f32_convert_u_i32="f32.convert_u/i32" 193 | op_f64_convert_u_i32="f64.convert_u/i32" 194 | op_f32_convert_u_i64="f32.convert_u/i64" 195 | op_f64_convert_u_i64="f64.convert_u/i64" 196 | op_f64_promote_f32="f64.promote/f32" 197 | op_f32_demote_f64="f32.demote/f64" 198 | op_f32_reinterpret_i32="f32.reinterpret/i32" 199 | op_i32_reinterpret_f32="i32.reinterpret/f32" 200 | op_f64_reinterpret_i64="f64.reinterpret/i64" 201 | op_i64_reinterpret_f64="i64.reinterpret/f64" 202 | op_select="select" 203 | op_unreachable="unreachable" 204 | op_memory_size="memory.size" 205 | op_memory_grow="memory.grow" 206 | op_type="type" 207 | op_func="func" 208 | op_param="param" 209 | op_result="result" 210 | op_local="local" 211 | op_global="global" 212 | op_module="module" 213 | op_table="table" 214 | op_memory="memory" 215 | op_table="start" 216 | op_elem="elem" 217 | op_data="data" 218 | op_offset="offset" 219 | op_align="align=" 220 | op_import="import" 221 | op_export="export" 222 | op_register="register" 223 | op_invoke="invoke" 224 | op_get="get" 225 | op_assert_malformed="assert_malformed" 226 | op_assert_invalid="assert_invalid" 227 | op_assert_unlinkable="assert_unlinkable" 228 | op_assert_return="assert_return" 229 | op_assert_trap="assert_trap" 230 | op_assert_exhaustion="assert_exhaustion" -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # WARF - WebAssembly Runtimes Fuzzing project 2 | 3 | Goal of this project is to improve security and resilience of WebAssembly VMs/runtimes/parsers using different fuzzing techniques. 4 | 5 | ## Quick Start (using docker) 6 | 7 | - Clone the project 8 | ``` sh 9 | # Install WARF 10 | $ git clone --depth 1 https://github.com/pventuzelo/wasm_runtimes_fuzzing 11 | $ cd wasm_runtimes_fuzzing/warf 12 | ``` 13 | 14 | Build warf with docker: 15 | ``` sh 16 | # Build warf docker 17 | $ make docker 18 | # Optional: Create an alias 19 | $ alias warf="docker run -it -v `pwd`/workspace:/warf/workspace warf" 20 | # ==> workspace folder is shared between your host and docker container. 21 | ``` 22 | NOTE: If you are on running on `Ubuntu`, installation without docker can be found [here](docs/INSTALL.md). 23 | 24 | 25 | - Run warf cli: 26 | ``` sh 27 | $ warf help 28 | 29 | WARF - WebAssembly Runtimes Fuzzing project 30 | USAGE: 31 | warf 32 | FLAGS: 33 | -h, --help Prints help information 34 | -V, --version Prints version information 35 | SUBCOMMANDS: 36 | benchmark-all Run WebAssembly module on all targets with benchmark 37 | build Build all targets for this specific fuzzer 38 | continuously Run all fuzz targets 39 | debug Debug one target 40 | execute-all Run WebAssembly module on all targets 41 | help Prints this message or the help of the given subcommand(s) 42 | list List all available targets 43 | target Run one target with specific fuzzer 44 | ``` 45 | NOTE: Details about the different warf subcommands [here](docs/WARF_SUBCOMMANDS.md). 46 | 47 | - List available fuzzing targets: 48 | ``` sh 49 | $ warf list 50 | 51 | wasmi_validate 52 | wasmi_instantiate 53 | parity_wasm_deserialize 54 | [...] 55 | binaryen_ffi 56 | wabt_wasm2wat_all_feat_ffi 57 | wabt_validate_ffi 58 | ``` 59 | 60 | - Run fuzzing on a target: 61 | ``` sh 62 | $ warf target wasmer_validate 63 | 64 | [...] 65 | 66 | ------------------------[ 0 days 00 hrs 00 mins 02 secs ]---------------------- 67 | Iterations : 272,647 [272.65k] 68 | Mode [3/3] : Feedback Driven Mode 69 | Target : hfuzz_target/x86_64-unknown-linux-gnu/release/wasmer_validate 70 | Threads : 4, CPUs: 8, CPU%: 529% [66%/CPU] 71 | Speed : 171,238/sec [avg: 136,323] 72 | Crashes : 0 [unique: 0, blacklist: 0, verified: 0] 73 | Timeouts : 0 [10 sec] 74 | Corpus Size : 754, max: 8,192 bytes, init: 1,126 files 75 | Cov Update : 0 days 00 hrs 00 mins 01 secs ago 76 | Coverage : edge: 3,194/58,784 [5%] pc: 2 cmp: 41,653 77 | ---------------------------------- [ LOGS ] ------------------/ honggfuzz 2.0 /- 78 | Size:77 (i,b,hw,ed,ip,cmp): 0/0/0/1/0/0, Tot:0/0/0/3159/2/41623 79 | [...] 80 | ``` 81 | 82 | # Tests 83 | 84 | Tests are documented inside the `Makefile`: 85 | ``` sh 86 | $ make help 87 | Management commands for warf 88 | 89 | Usage: 90 | make build Compile the project locally. 91 | make docker Build a docker image for this project. 92 | make corpora TODO 93 | 94 | make fmt Run Rust fmt. 95 | make clean Clean only warf binary. 96 | make clean-all Clean all (warf && compiled fuzz target harnesses). 97 | 98 | make test Simple test to check warf and execute_all is working. 99 | make test-bench Simple benchmark using execute_all. 100 | make test-debug Test running a simple wasm to a debugging tool. 101 | make test-{libfuzzer, honggfuzz, afl} Test one fuzzing hardness over choosen fuzzer. 102 | make test-continuously-{libfuzzer, hfuzz, afl} Test all fuzzing hardness over choosen fuzzer. 103 | make test-all Test all fuzzing hardness over all fuzzers. 104 | 105 | ``` 106 | 107 | If you are using docker, try: 108 | ``` sh 109 | make docker-test 110 | make docker-test-all 111 | ``` 112 | 113 | # Future of the project 114 | 115 | Differents open-source projects (WebAssembly VMs/runtimes/parsers) will be integrated to WARF along the development: 116 | - Integration details [here](docs/INTEGRATION.md). 117 | - Global roadmap [here](docs/ROADMAP.md). 118 | 119 | # Trophies 120 | 121 | This tool helped to find the following bugs/vulnerabilities (crashing files are inside `trophies` folder): 122 | - wasmer/wasmer_clif_fork_wasm: [index out of bounds panic](https://github.com/wasmerio/wasmer/issues/1372) 123 | - binaryen: [segfault / out-of-bounds read in `WasmBinaryBuilder::readImports`](https://github.com/WebAssembly/binaryen/issues/2751) - **FIXED** 124 | - wabt: [SIGABRT due to std::bad_alloc exception (resizing wasm br_table)](https://github.com/WebAssembly/wabt/issues/1386) - **FIXED** 125 | - wasmtime: [assertion failed in wasmtime_debug::transform::simulate::generate_simulated_dwarf](https://github.com/bytecodealliance/wasmtime/issues/1506) - **FIXED** 126 | - wasmtime: [assertion failed or unimplemented panic when table type is not anyref](https://github.com/bytecodealliance/wasmtime/issues/1601) - **FIXED** 127 | - wabt: [[wasm2wat] Assertion failure in `BinaryReaderIR::OnCallIndirectExpr`](https://github.com/WebAssembly/wabt/issues/1413) - **FIXED** 128 | - wabt: [[wasm2wat] Assertion failure in `BinaryReaderIR::OnReturnCallIndirectExpr`](https://github.com/WebAssembly/wabt/issues/1414) - **FIXED** 129 | - wabt: [Incorrect validation of module with malformed alignment by wabt](https://github.com/WebAssembly/wabt/issues/1453) - **FIXED** 130 | - wabt: [[wasm2wat] Incorrect rejection of valid module](https://github.com/WebAssembly/wabt/issues/1455) 131 | - wain: [unwrap panic while parsing invalid wasm module](https://github.com/rhysd/wain/issues/29) - **FIXED** 132 | - wain: [memory allocation failed error during parsing](https://github.com/rhysd/wain/issues/30) - **FIXED** 133 | - wasm3: [segfault / assertion failed in `GetStackTopIndex`](https://github.com/wasm3/wasm3/issues/151) - **FIXED** 134 | - wasm3: [segfault / null pointer dereference in `GetFunctionNumReturns`](https://github.com/wasm3/wasm3/issues/152) - **FIXED** 135 | - wasm3: [heap buffer overflow in `ParseSection_Export`](https://github.com/wasm3/wasm3/issues/153) - **FIXED** 136 | - wasm3: [SIGILL in `Compile_BlockStatements`](https://github.com/wasm3/wasm3/issues/154) - **FIXED** 137 | - wain: ["index out of bounds" in wain validate](https://github.com/rhysd/wain/issues/39) - **FIXED** 138 | - wasmprinter: [Resources exhaustion (CPU/MEM) using `wasmprinter::print_bytes()`](https://github.com/bytecodealliance/wasm-tools/issues/52) - **FIXED** 139 | - wasm3: [heap-use-after-free in `ReadLebUnsigned`](https://github.com/wasm3/wasm3/issues/156) - **FIXED** 140 | - wasm3: [global-buffer-overflow in `Compile_BlockStatements`](https://github.com/wasm3/wasm3/issues/157) - **FIXED** 141 | - wasm3: [out of bound read in `Read_f64`](https://github.com/wasm3/wasm3/issues/158) - **FIXED** 142 | - wasm3: [heap-buffer-overflow in `Compile_BlockStatements` (line 2169)](https://github.com/wasm3/wasm3/issues/159) - **FIXED** 143 | 144 | # Thanks 145 | 146 | - [Web 3 Foundation](https://web3.foundation/) for sponsoring this project. 147 | - [Rust Fuzzing Authority](https://github.com/rust-fuzz) for Rust fuzzing tools. 148 | 149 | 150 | # Trainings & Contact 151 | 152 | Patrick Ventuzelo - [@pat_ventuzelo](https://twitter.com/pat_ventuzelo) 153 | * Independent Security Researcher / Trainer. 154 | * FREE online courses: [here](https://academy.fuzzinglabs.com/) 155 | -------------------------------------------------------------------------------- /docs/WARF_SUBCOMMANDS.md: -------------------------------------------------------------------------------- 1 | # WARF SUBCOMMANDS 2 | 3 | The main goal of this tool is to provide an easy way to fuzz WebAssembly VMs/runtimes. 4 | In addition to finding bugs, fuzzing will also generated samples/inputs that can be reused as unittest. 5 | 6 | 7 | Main features are: 8 | - Automatic fuzzing of runtimes harnesses (without any user interaction) 9 | - Multiple fuzzing engines available (honggfuzz, afl, libfuzzer) 10 | - Multi-threading (depending of the fuzzer, only honggfuzz for now) 11 | - Crash report/detection 12 | 13 | 14 | # Subcommands 15 | 16 | List all subcommands with `help`: 17 | ``` sh 18 | $ ./warf help 19 | 20 | [...] 21 | SUBCOMMANDS: 22 | benchmark-all Run WebAssembly module on all targets with benchmark 23 | build Build all targets for this specific fuzzer 24 | continuously Run all fuzz targets 25 | debug Debug one target 26 | execute-all Run WebAssembly module on all targets 27 | help Prints this message or the help of the given subcommand(s) 28 | list List all available targets 29 | target Run one target with specific fuzzer 30 | ``` 31 | 32 | ## List available targets (`list`) 33 | 34 | Available fuzzing targets can be listed with: 35 | ```sh 36 | $ ./warf list 37 | 38 | wasmi_validate 39 | wasmi_instantiate 40 | parity_wasm_deserialize 41 | [...] 42 | binaryen_ffi 43 | wabt_wasm2wat_all_feat_ffi 44 | wabt_validate_ffi 45 | ``` 46 | 47 | ## Fuzzing one target (`target`) 48 | 49 | - Run fuzzing on a target (default fuzzing engine is `honggfuzz`): 50 | ``` sh 51 | $ ./warf target wasmer_validate 52 | 53 | [...] 54 | 55 | ------------------------[ 0 days 00 hrs 00 mins 02 secs ]---------------------- 56 | Iterations : 272,647 [272.65k] 57 | Mode [3/3] : Feedback Driven Mode 58 | Target : hfuzz_target/x86_64-unknown-linux-gnu/release/wasmer_validate 59 | Threads : 4, CPUs: 8, CPU%: 529% [66%/CPU] 60 | Speed : 171,238/sec [avg: 136,323] 61 | Crashes : 0 [unique: 0, blacklist: 0, verified: 0] 62 | Timeouts : 0 [10 sec] 63 | Corpus Size : 754, max: 8,192 bytes, init: 1,126 files 64 | Cov Update : 0 days 00 hrs 00 mins 01 secs ago 65 | Coverage : edge: 3,194/58,784 [5%] pc: 2 cmp: 41,653 66 | ---------------------------------- [ LOGS ] ------------------/ honggfuzz 2.0 /- 67 | Size:77 (i,b,hw,ed,ip,cmp): 0/0/0/1/0/0, Tot:0/0/0/3159/2/41623 68 | [...] 69 | ``` 70 | 71 | - Available options: 72 | ``` sh 73 | $ ./warf target wasmer_validate --help 74 | 75 | [...] 76 | 77 | OPTIONS: 78 | --fuzzer Which fuzzer to run [default: Honggfuzz] [possible values: Afl, Honggfuzz, Libfuzzer] 79 | -n, --thread Set number of thread (only for hfuzz) 80 | -t, --timeout Set timeout per target 81 | 82 | ARGS: 83 | Which target to run 84 | ``` 85 | NOTE: More informations about advanced options and the different fuzzing engines can be found [here](warf_advanced_options.md). 86 | 87 | 88 | ## Continuous fuzzing (`continuously`) 89 | 90 | warf in continuous mode will executed all target once then stop. 91 | 92 | Help: 93 | ``` sh 94 | $ ./warf continuously --help 95 | Run all fuzz targets 96 | 97 | USAGE: 98 | cli continuously [FLAGS] [OPTIONS] 99 | 100 | FLAGS: 101 | --cargo-update 102 | -h, --help Prints help information 103 | -i, --infinite 104 | -V, --version Prints version information 105 | 106 | OPTIONS: 107 | -q, --filter Only run target containing this string 108 | --fuzzer Which fuzzer to run [default: Honggfuzz] [possible values: Afl, Honggfuzz, Libfuzzer] 109 | -n, --thread Set number of thread (only for hfuzz) 110 | -t, --timeout Set timeout per target [default: 10] 111 | ``` 112 | 113 | Prefered command: 114 | ``` sh 115 | $ ./warf continuously -i -t 600 116 | # -i => infinite mode. 117 | # -t => timeout of 10 min, will switch to another fuzzing target every 10 min. 118 | ``` 119 | 120 | ## Debug one target (`debug`) 121 | 122 | This command will create a simple debugging tool for the choosen target allowing you to easily analyze the root cause of a crash as shown inside this tutorial: [how_to_analyze_a_crash.md](how_to_analyze_a_crash.md). 123 | 124 | NOTE: all debugging tools generated with `debug` subcommand are available inside: `workspace/debug/target/debug/`. 125 | 126 | 127 | ## Execute one wasm module throw all targets (`execute-all`) 128 | 129 | This command will create, build and execute a standalone binary running one wasm module throw all fuzzing targets. 130 | NOTE: This binary will be stored in `workspace/exec_all` allowing you to directly call it later without re-compilation. 131 | NOTE 2: Targets do not handle the same type of data that's why it can be perfectly valid to have a target returning an error e.g. if you provide a wasm module to `wat_parser`, it will return an error. 132 | 133 | ``` sh 134 | $ ./warf execute-all workspace/corpora/wasm/fib.wasm 135 | 136 | [...] 137 | 138 | [WARF] execute_all compiled here: "XXX/wasm_runtimes_fuzzing/warf/workspace/exec_all" 139 | Execution of all runtime engine 140 | file_to_process: "workspace/corpora/wasm/fib.wasm" 141 | 142 | [O] wasmi_validate: Ok() 143 | [O] wasmi_instantiate: Ok() 144 | [O] parity_wasm_deserialize: Ok() 145 | [O] wasmer_validate: Ok() 146 | [O] wasmer_compile_clif: Ok() 147 | [O] wasmer_compile_singlepass: Ok() 148 | [O] wasmer_instantiate: Ok() 149 | [O] wasmtime_validate: Ok() 150 | [O] wasmtime_validate_all_feat: Ok() 151 | [O] wasmtime_compile: Ok() 152 | [O] wasmtime_compile_all_cranelift: Ok() 153 | [X] wasmtime_compile_all_lightbeam: Err() 154 | [O] wasmtime_instantiate_all_cranelift: Ok() 155 | [X] wasmtime_instantiate_all_lightbeam: Err() 156 | [X] lightbeam_translate: Err() 157 | [O] wasmparser_parser: Ok() 158 | [O] wasmparser_validate: Ok() 159 | [O] wasmparser_validate_all_feat: Ok() 160 | [O] binaryen_ffi: Ok() 161 | [O] binaryen_optimize_ffi: Ok() 162 | [O] wabt_wasm2wat_all_feat_ffi: Ok() 163 | [O] wabt_validate_ffi: Ok() 164 | 165 | No crash, everything is OK 166 | ``` 167 | 168 | ## Benchmark execution targets speed (`benchmark-all`) 169 | 170 | This command will add benchmarking information into `exec_all` binary and produce the following result during execution: 171 | 172 | ``` sh 173 | $ ./warf benchmark-all workspace/corpora/wasm/fib.wasm 174 | 175 | [...] 176 | 177 | [WARF] execute_all compiled here: "XXX/wasm_runtimes_fuzzing/warf/workspace/exec_all" 178 | Execution of all runtime engine 179 | file_to_process: "workspace/corpora/wasm/fib.wasm" 180 | 181 | [O] wasmi_validate: Ok() 182 | benchmark (sec): 0.0000001458 183 | [O] wasmi_instantiate: Ok() 184 | benchmark (sec): 0.0000000711 185 | [O] parity_wasm_deserialize: Ok() 186 | benchmark (sec): 0.0000000218 187 | [O] wasmer_validate: Ok() 188 | benchmark (sec): 0.0000000573 189 | [O] wasmer_compile_clif: Ok() 190 | benchmark (sec): 0.0000023549 191 | [O] wasmer_compile_singlepass: Ok() 192 | benchmark (sec): 0.0000006215 193 | [O] wasmer_instantiate: Ok() 194 | benchmark (sec): 0.0000009492 195 | [O] wasmtime_validate: Ok() 196 | benchmark (sec): 0.0000002413 197 | [O] wasmtime_validate_all_feat: Ok() 198 | benchmark (sec): 0.0000000390 199 | [O] wasmtime_compile: Ok() 200 | benchmark (sec): 0.0000008680 201 | [O] wasmtime_compile_all_cranelift: Ok() 202 | benchmark (sec): 0.0000009030 203 | [X] wasmtime_compile_all_lightbeam: Err() 204 | benchmark (sec): 0.0000000171 205 | [O] wasmtime_instantiate_all_cranelift: Ok() 206 | benchmark (sec): 0.0000012563 207 | [X] wasmtime_instantiate_all_lightbeam: Err() 208 | benchmark (sec): 0.0000000118 209 | [X] lightbeam_translate: Err() 210 | benchmark (sec): 0.0000000257 211 | [O] wasmparser_parser: Ok() 212 | benchmark (sec): 0.0000000154 213 | [O] wasmparser_validate: Ok() 214 | benchmark (sec): 0.0000000267 215 | [O] wasmparser_validate_all_feat: Ok() 216 | benchmark (sec): 0.0000000147 217 | [O] binaryen_ffi: Ok() 218 | benchmark (sec): 0.0000001865 219 | [O] binaryen_optimize_ffi: Ok() 220 | benchmark (sec): 0.0000063538 221 | [O] wabt_wasm2wat_all_feat_ffi: Ok() 222 | benchmark (sec): 0.0000000897 223 | [O] wabt_validate_ffi: Ok() 224 | benchmark (sec): 0.0000000295 225 | 226 | No crash, everything is OK 227 | ``` 228 | -------------------------------------------------------------------------------- /warf/src/main.rs: -------------------------------------------------------------------------------- 1 | extern crate regex; 2 | extern crate structopt; 3 | #[macro_use] 4 | extern crate clap; 5 | #[macro_use] 6 | extern crate failure; 7 | 8 | // Strum contains all the trait definitions 9 | extern crate strum; 10 | #[macro_use] 11 | extern crate strum_macros; 12 | 13 | use crate::strum::IntoEnumIterator; 14 | use failure::Error; 15 | use structopt::StructOpt; 16 | 17 | mod debug; 18 | mod env; 19 | mod exec_all; 20 | mod fuzzers; 21 | mod rust_fuzzers; 22 | mod targets; 23 | mod utils; 24 | 25 | /// WARF - WebAssembly Runtimes Fuzzing project 26 | #[derive(StructOpt, Debug)] 27 | enum Cli { 28 | /// Run all fuzz targets 29 | #[structopt(name = "continuously")] 30 | Continuous { 31 | /// Only run target containing this string 32 | #[structopt(short = "q", long = "filter")] 33 | filter: Option, 34 | /// Which fuzzer to run 35 | #[structopt( 36 | short = "f", 37 | long = "fuzzer", 38 | default_value = "Honggfuzz", 39 | raw( 40 | possible_values = "&fuzzers::Fuzzer::variants()", 41 | case_insensitive = "true" 42 | ) 43 | )] 44 | fuzzer: fuzzers::Fuzzer, 45 | /// Set timeout per target 46 | #[structopt(short = "t", long = "timeout", default_value = "10")] 47 | timeout: i32, 48 | /// Set number of thread 49 | #[structopt(short = "n", long = "thread")] 50 | thread: Option, 51 | /// Set seed 52 | #[structopt(short = "s", long = "seed")] 53 | seed: Option, 54 | /// Set a compilation Sanitizer (advanced) 55 | #[structopt( 56 | long = "sanitizer", 57 | raw( 58 | possible_values = "&fuzzers::Sanitizer::variants()", 59 | case_insensitive = "true" 60 | ) 61 | )] 62 | sanitizer: Option, 63 | // Run until the end of time (or Ctrl+C) 64 | #[structopt(short = "i", long = "infinite")] 65 | infinite: bool, 66 | }, 67 | /// Run one target with specific fuzzer 68 | #[structopt(name = "target")] 69 | Run { 70 | /// Which target to run 71 | target: String, 72 | /// Which fuzzer to run 73 | #[structopt( 74 | short = "f", 75 | long = "fuzzer", 76 | default_value = "Honggfuzz", 77 | raw( 78 | possible_values = "&fuzzers::Fuzzer::variants()", 79 | case_insensitive = "true" 80 | ) 81 | )] 82 | fuzzer: fuzzers::Fuzzer, 83 | /// Set timeout 84 | #[structopt(short = "t", long = "timeout")] 85 | timeout: Option, 86 | /// Set number of thread (only for hfuzz) 87 | #[structopt(short = "n", long = "thread")] 88 | thread: Option, 89 | /// Set seed 90 | #[structopt(short = "s", long = "seed")] 91 | seed: Option, 92 | /// Set dictionary file 93 | #[structopt(short = "d", long = "dict")] 94 | dict: Option, 95 | /// Set a compilation Sanitizer (advanced) 96 | #[structopt( 97 | long = "sanitizer", 98 | raw( 99 | possible_values = "&fuzzers::Sanitizer::variants()", 100 | case_insensitive = "true" 101 | ) 102 | )] 103 | sanitizer: Option, 104 | }, 105 | /// Debug one target 106 | #[structopt(name = "debug")] 107 | Debug { 108 | /// Which target to debug 109 | target: String, 110 | }, 111 | /// List all available targets 112 | #[structopt(name = "list")] 113 | ListTargets, 114 | /// Run WebAssembly module on all targets 115 | #[structopt(name = "execute-all")] 116 | ExecuteAll { 117 | /// Which wasm to execute 118 | wasm: String, 119 | }, 120 | /// Run WebAssembly module on all targets with benchmark 121 | #[structopt(name = "benchmark-all")] 122 | BenchmarkAll { 123 | /// Which wasm to execute 124 | wasm: String, 125 | }, 126 | } 127 | 128 | /// Main function catching errors 129 | fn main() { 130 | if let Err(e) = run() { 131 | eprintln!("{}", e); 132 | for cause in e.iter_chain().skip(1) { 133 | eprintln!("caused by: {}", cause); 134 | } 135 | ::std::process::exit(1); 136 | } 137 | } 138 | 139 | /// Parsing of CLI arguments 140 | fn run() -> Result<(), Error> { 141 | use Cli::*; 142 | let cli = Cli::from_args(); 143 | 144 | match cli { 145 | ExecuteAll { wasm } => { 146 | exec_all::run_exec_all(wasm, false)?; 147 | } 148 | BenchmarkAll { wasm } => { 149 | exec_all::run_exec_all(wasm, true)?; 150 | } 151 | // list all targets 152 | ListTargets => { 153 | list_targets()?; 154 | } 155 | // Fuzz one target 156 | Run { 157 | target, 158 | fuzzer, 159 | timeout, 160 | thread, 161 | seed, 162 | dict, 163 | sanitizer, 164 | } => { 165 | let config = fuzzers::FuzzerConfig { 166 | timeout, 167 | thread, 168 | sanitizer, 169 | seed, 170 | dict, 171 | }; 172 | run_target(target, fuzzer, config)?; 173 | } 174 | // Debug one target 175 | Debug { target } => { 176 | debug::run_debug(target)?; 177 | } 178 | // Fuzz multiple targets 179 | Continuous { 180 | filter, 181 | timeout, 182 | fuzzer, 183 | thread, 184 | seed, 185 | sanitizer, 186 | infinite, 187 | } => { 188 | let config = fuzzers::FuzzerConfig { 189 | timeout: Some(timeout), 190 | thread, 191 | sanitizer, 192 | seed, 193 | dict: None, 194 | }; 195 | run_continuously(filter, fuzzer, config, infinite)?; 196 | } 197 | } 198 | Ok(()) 199 | } 200 | 201 | /// List all targets available 202 | fn list_targets() -> Result<(), Error> { 203 | for target in targets::get_targets() { 204 | println!("{}", target); 205 | } 206 | Ok(()) 207 | } 208 | 209 | /// Run fuzzing on only one target 210 | fn run_target( 211 | target: String, 212 | fuzzer: fuzzers::Fuzzer, 213 | config: fuzzers::FuzzerConfig, 214 | ) -> Result<(), Error> { 215 | let target = match targets::Targets::iter().find(|x| x.name() == target) { 216 | None => bail!( 217 | "Don't know target `{}`. {}", 218 | target, 219 | if let Some(alt) = utils::did_you_mean(&target, &targets::get_targets()) { 220 | format!("Did you mean `{}`?", alt) 221 | } else { 222 | "".into() 223 | } 224 | ), 225 | Some(t) => t, 226 | }; 227 | 228 | use fuzzers::Fuzzer::*; 229 | match fuzzer { 230 | Afl => { 231 | let afl = rust_fuzzers::FuzzerAfl::new(config)?; 232 | afl.run(target)?; 233 | } 234 | Honggfuzz => { 235 | let hfuzz = rust_fuzzers::FuzzerHfuzz::new(config)?; 236 | hfuzz.run(target)?; 237 | } 238 | Libfuzzer => { 239 | let lfuzz = rust_fuzzers::FuzzerLibfuzzer::new(config)?; 240 | lfuzz.run(target)?; 241 | } 242 | } 243 | Ok(()) 244 | } 245 | 246 | /// Run fuzzing on multiple target matching the filter option 247 | fn run_continuously( 248 | filter: Option, 249 | fuzzer: fuzzers::Fuzzer, 250 | config: fuzzers::FuzzerConfig, 251 | infinite: bool, 252 | ) -> Result<(), Error> { 253 | let run = |target: &str| -> Result<(), Error> { 254 | let target = match targets::Targets::iter().find(|x| x.name() == target) { 255 | None => bail!( 256 | "Don't know target `{}`. {}", 257 | target, 258 | if let Some(alt) = utils::did_you_mean(&target, &targets::get_targets()) { 259 | format!("Did you mean `{}`?", alt) 260 | } else { 261 | "".into() 262 | } 263 | ), 264 | Some(t) => t, 265 | }; 266 | 267 | use fuzzers::Fuzzer::*; 268 | match fuzzer { 269 | Afl => { 270 | let hfuzz = rust_fuzzers::FuzzerAfl::new(config.clone())?; 271 | hfuzz.run(target)?; 272 | } 273 | Honggfuzz => { 274 | let hfuzz = rust_fuzzers::FuzzerHfuzz::new(config.clone())?; 275 | hfuzz.run(target)?; 276 | } 277 | Libfuzzer => { 278 | let hfuzz = rust_fuzzers::FuzzerLibfuzzer::new(config.clone())?; 279 | hfuzz.run(target)?; 280 | } 281 | } 282 | Ok(()) 283 | }; 284 | 285 | let targets = targets::get_targets(); 286 | let targets = targets 287 | .iter() 288 | .filter(|x| filter.as_ref().map(|f| x.contains(f)).unwrap_or(true)); 289 | 290 | 'cycle: loop { 291 | 'targets_pass: for target in targets.clone() { 292 | if let Err(e) = run(target) { 293 | match e.downcast::() { 294 | Ok(_) => { 295 | println!("Fuzzer failed so we'll continue with the next one"); 296 | continue 'targets_pass; 297 | } 298 | Err(other_error) => return Err(other_error), 299 | } 300 | } 301 | } 302 | 303 | if !infinite { 304 | break 'cycle; 305 | } 306 | } 307 | Ok(()) 308 | } 309 | -------------------------------------------------------------------------------- /warf/src/targets.rs: -------------------------------------------------------------------------------- 1 | use failure::Error; 2 | use strum::IntoEnumIterator; 3 | 4 | use crate::env::{targets_dir, workspace_dir}; 5 | use crate::utils::copy_dir; 6 | 7 | #[derive(Copy, Clone, Debug, EnumIter)] 8 | pub enum Targets { 9 | // wasmi 10 | WasmiValidate, 11 | WasmiInstantiate, 12 | // parity_wasm 13 | ParityWasmDeserialize, 14 | // wasmer 15 | WasmerValidate, 16 | WasmerCompileClif, 17 | WasmerCompileSinglepass, 18 | WasmerInstantiate, 19 | // wasmtime 20 | WasmtimeValidate, 21 | WasmtimeValidateAllFeat, 22 | WasmtimeCompile, 23 | WasmtimeCompileAllCranelift, 24 | WasmtimeInstantiateAllCranelift, 25 | // wasmparser 26 | WasmparserParser, 27 | WasmparserValidate, 28 | WasmparserValidateAllFeat, 29 | // binaryen_ffi 30 | BinaryenFfi, 31 | BinaryenOptimizeFfi, 32 | // wabt_ffi 33 | WabtWasm2watAllFeatFfi, 34 | WabtValidateFfi, 35 | WabtWat2WasmAllFeatFfi, 36 | // wasmprinter 37 | WasmprinterParser, 38 | // wain 39 | WainParser, 40 | WainValidate, 41 | // wat 42 | WatParser, 43 | // wast 44 | WastParser, 45 | // wasm3 46 | Wasm3Parser, 47 | // fizzy, 48 | FizzyValidate, 49 | // differential fuzzing 50 | DiffParsing, 51 | DiffValidateAllFeat, 52 | DiffInstantiate, 53 | DiffWatParsing, 54 | } 55 | 56 | impl Targets { 57 | pub fn name(&self) -> String { 58 | match &self { 59 | // wasmi 60 | Targets::WasmiValidate => "wasmi_validate", 61 | Targets::WasmiInstantiate => "wasmi_instantiate", 62 | // parity_wasm 63 | Targets::ParityWasmDeserialize => "parity_wasm_deserialize", 64 | // wasmer 65 | Targets::WasmerValidate => "wasmer_validate", 66 | Targets::WasmerCompileClif => "wasmer_compile_clif", 67 | Targets::WasmerCompileSinglepass => "wasmer_compile_singlepass", 68 | Targets::WasmerInstantiate => "wasmer_instantiate", 69 | // wasmtime 70 | Targets::WasmtimeValidate => "wasmtime_validate", 71 | Targets::WasmtimeValidateAllFeat => "wasmtime_validate_all_feat", 72 | Targets::WasmtimeCompile => "wasmtime_compile", 73 | Targets::WasmtimeCompileAllCranelift => "wasmtime_compile_all_cranelift", 74 | Targets::WasmtimeInstantiateAllCranelift => "wasmtime_instantiate_all_cranelift", 75 | // wasmparser 76 | Targets::WasmparserParser => "wasmparser_parser", 77 | Targets::WasmparserValidate => "wasmparser_validate", 78 | Targets::WasmparserValidateAllFeat => "wasmparser_validate_all_feat", 79 | // binaryen_ffi 80 | Targets::BinaryenFfi => "binaryen_ffi", 81 | Targets::BinaryenOptimizeFfi => "binaryen_optimize_ffi", 82 | // wabt_ffi 83 | Targets::WabtWasm2watAllFeatFfi => "wabt_wasm2wat_all_feat_ffi", 84 | Targets::WabtValidateFfi => "wabt_validate_ffi", 85 | Targets::WabtWat2WasmAllFeatFfi => "wabt_wat2wasm_ffi", 86 | // wasmprinter 87 | Targets::WasmprinterParser => "wasmprinter_parser", 88 | // wain 89 | Targets::WainParser => "wain_parser", 90 | Targets::WainValidate => "wain_validate", 91 | // wat 92 | Targets::WatParser => "wat_parser", 93 | // wast 94 | Targets::WastParser => "wast_parser", 95 | // wasm3 96 | Targets::Wasm3Parser => "wasm3_parser_ffi", 97 | // fizzy 98 | Targets::FizzyValidate => "fizzy_validate", 99 | // differential fuzzing 100 | Targets::DiffParsing => "diff_parsing", 101 | Targets::DiffValidateAllFeat => "diff_all_validate", 102 | Targets::DiffInstantiate => "diff_instantiate", 103 | Targets::DiffWatParsing => "diff_wat_parsing", 104 | } 105 | .to_string() 106 | } 107 | 108 | pub fn corpora(&self) -> String { 109 | match &self { 110 | // wasmi 111 | Targets::WasmiValidate 112 | | Targets::WasmiInstantiate 113 | // parity_wasm 114 | | Targets::ParityWasmDeserialize 115 | // wasmer 116 | | Targets::WasmerValidate 117 | | Targets::WasmerCompileClif 118 | | Targets::WasmerCompileSinglepass 119 | | Targets::WasmerInstantiate 120 | // wasmtime 121 | | Targets::WasmtimeValidate 122 | | Targets::WasmtimeValidateAllFeat 123 | | Targets::WasmtimeCompile 124 | | Targets::WasmtimeCompileAllCranelift 125 | | Targets::WasmtimeInstantiateAllCranelift 126 | // wasmparser 127 | | Targets::WasmparserParser 128 | | Targets::WasmparserValidate 129 | | Targets::WasmparserValidateAllFeat 130 | // binaryen_ffi 131 | | Targets::BinaryenFfi 132 | | Targets::BinaryenOptimizeFfi 133 | // wabt_ffi 134 | | Targets::WabtWasm2watAllFeatFfi 135 | | Targets::WabtValidateFfi => "wasm", 136 | Targets::WabtWat2WasmAllFeatFfi => "wat", 137 | // wasmprinter 138 | Targets::WasmprinterParser 139 | // wain 140 | | Targets::WainParser 141 | | Targets::WainValidate => "wasm", 142 | // wat 143 | Targets::WatParser => "wat", 144 | // wast 145 | Targets::WastParser => "wast", 146 | // wasm3 147 | Targets::Wasm3Parser => "wasm", 148 | // fizzy 149 | Targets::FizzyValidate => "wasm", 150 | // differential fuzzing 151 | Targets::DiffParsing 152 | | Targets::DiffValidateAllFeat 153 | | Targets::DiffInstantiate => "wasm", 154 | Targets::DiffWatParsing => "wat", 155 | } 156 | .to_string() 157 | } 158 | 159 | pub fn template(&self) -> String { 160 | match &self { 161 | // wasmi 162 | Targets::WasmiValidate 163 | | Targets::WasmiInstantiate 164 | // parity_wasm 165 | | Targets::ParityWasmDeserialize 166 | // wasmer 167 | | Targets::WasmerValidate 168 | | Targets::WasmerCompileClif 169 | | Targets::WasmerCompileSinglepass 170 | | Targets::WasmerInstantiate 171 | // wasmtime 172 | | Targets::WasmtimeValidate 173 | | Targets::WasmtimeValidateAllFeat 174 | | Targets::WasmtimeCompile 175 | | Targets::WasmtimeCompileAllCranelift 176 | | Targets::WasmtimeInstantiateAllCranelift 177 | // wasmparser 178 | | Targets::WasmparserParser 179 | | Targets::WasmparserValidate 180 | | Targets::WasmparserValidateAllFeat 181 | // binaryen_ffi 182 | | Targets::BinaryenFfi 183 | | Targets::BinaryenOptimizeFfi 184 | // wabt_ffi 185 | | Targets::WabtWasm2watAllFeatFfi 186 | | Targets::WabtValidateFfi 187 | | Targets::WabtWat2WasmAllFeatFfi 188 | // wasmprinter 189 | | Targets::WasmprinterParser 190 | // wain 191 | | Targets::WainParser 192 | | Targets::WainValidate 193 | // wat 194 | | Targets::WatParser 195 | // wast 196 | | Targets::WastParser 197 | // wasm3 198 | | Targets::Wasm3Parser 199 | // fizzy 200 | | Targets::FizzyValidate 201 | // differential fuzzing 202 | | Targets::DiffParsing 203 | | Targets::DiffValidateAllFeat 204 | | Targets::DiffInstantiate 205 | | Targets::DiffWatParsing => "template.rs", 206 | } 207 | .to_string() 208 | } 209 | 210 | pub fn language(&self) -> String { 211 | match &self { 212 | // wasmi 213 | Targets::WasmiValidate 214 | | Targets::WasmiInstantiate 215 | // parity_wasm 216 | | Targets::ParityWasmDeserialize 217 | // wasmer 218 | | Targets::WasmerValidate 219 | | Targets::WasmerCompileClif 220 | | Targets::WasmerCompileSinglepass 221 | | Targets::WasmerInstantiate 222 | // wasmtime 223 | | Targets::WasmtimeValidate 224 | | Targets::WasmtimeValidateAllFeat 225 | | Targets::WasmtimeCompile 226 | | Targets::WasmtimeCompileAllCranelift 227 | | Targets::WasmtimeInstantiateAllCranelift 228 | // wasmparser 229 | | Targets::WasmparserParser 230 | | Targets::WasmparserValidate 231 | | Targets::WasmparserValidateAllFeat 232 | // binaryen_ffi 233 | | Targets::BinaryenFfi 234 | | Targets::BinaryenOptimizeFfi 235 | // wabt_ffi 236 | | Targets::WabtWasm2watAllFeatFfi 237 | | Targets::WabtValidateFfi 238 | | Targets::WabtWat2WasmAllFeatFfi 239 | // wasmprinter 240 | | Targets::WasmprinterParser 241 | // wain 242 | | Targets::WainParser 243 | | Targets::WainValidate 244 | // wat 245 | | Targets::WatParser 246 | // wast 247 | | Targets::WastParser 248 | // wasm3 249 | | Targets::Wasm3Parser 250 | // fizzy 251 | | Targets::FizzyValidate 252 | // differential fuzzing 253 | | Targets::DiffParsing 254 | | Targets::DiffValidateAllFeat 255 | | Targets::DiffInstantiate 256 | | Targets::DiffWatParsing => "rust", 257 | } 258 | .to_string() 259 | } 260 | } 261 | 262 | pub fn get_targets() -> Vec { 263 | Targets::iter().map(|x| x.name()).collect() 264 | } 265 | 266 | pub fn prepare_targets_workspace() -> Result<(), Error> { 267 | let from = targets_dir()?; 268 | let workspace = workspace_dir()?; 269 | copy_dir(from, workspace)?; 270 | Ok(()) 271 | } 272 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [2020] [Patrick Ventuzelo] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /docs/INTEGRATION.md: -------------------------------------------------------------------------------- 1 | # Integration 2 | 3 | List of projects can be found below. This list is subject to changes in the future. 4 | 5 | Regarding APIs, we will focus first on apis in charge of the following operations: 6 | - [YES] parsing/deserialization. 7 | - [YES] validation. 8 | - [YES] instantiation. 9 | - [YES] execution. 10 | - [MAYBE] serialization. 11 | 12 | # Projects integrated 13 | 14 | Those projects **are already** supported/integrated. 15 | 16 | ## wasmi (Rust) 17 | 18 | Wasm interpreter in Rust: [github](https://github.com/paritytech/wasmi) / [documentation](https://paritytech.github.io/wasmi/wasmi/index.html) 19 | 20 |
Details 21 |

22 | 23 | - APIs: 24 | - `wasmi::Module::from_buffer`: Load, validate and prepare a `parity_wasm`'s `Module`. - [impl](https://github.com/paritytech/wasmi/blob/b67af25899874de7aac187e08e3b2a30d9bbc388/src/lib.rs#L426) 25 | - `validate_module`: A module validator function - [impl](https://github.com/paritytech/wasmi/blob/e8d5fb6c84edee2b43e99113cfdc19951520c29a/validation/src/lib.rs#L131) 26 | - `wasmi::ModuleInstance::new`: Runtime representation of a `wasmi::Module` - [example](https://github.com/paritytech/wasmi/blob/master/examples/interpret.rs#L34) 27 | 28 | - Examples: 29 | - [tests](https://github.com/paritytech/wasmi/blob/899cc32e45483fce12907f807ee9b09d837d2636/src/tests/wasm.rs) 30 | - [examples](https://github.com/paritytech/wasmi/tree/master/examples) 31 | - [fuzzing](https://github.com/paritytech/wasmi/blob/master/hfuzz/src/main.rs) 32 | - [fuzzing](https://github.com/paritytech/wasmi/tree/master/fuzz/fuzz_targets) 33 | 34 |

35 |
36 | 37 | ## wasmtime (Rust) 38 | 39 | Standalone JIT-style runtime for WebAssembly: [github](https://github.com/bytecodealliance/wasmtime) / [guide](https://bytecodealliance.github.io/wasmtime/) 40 | 41 |
Details 42 |

43 | 44 | - backends: 45 | - [cranelift](https://github.com/bytecodealliance/wasmtime/tree/master/cranelift) 46 | - [lightbeam](https://github.com/bytecodealliance/wasmtime/tree/master/crates/lightbeam) 47 | 48 | - APIs: 49 | - `oracles::compile`: Generic way to compile wasm module bytes - [example](https://github.com/bytecodealliance/wasmtime/blob/master/fuzz/fuzz_targets/compile.rs) 50 | - `oracles::instantiate`: Generic way to compile and instantiate wasm module bytes - [example](https://github.com/bytecodealliance/wasmtime/blob/master/fuzz/fuzz_targets/instantiate.rs) / [other](https://github.com/bytecodealliance/wasmtime/blob/b3ac71842183ca99cfa8a2d04e9a7ac5a2cee50d/crates/fuzzing/tests/regressions.rs) 51 | - `lightbeam::translate`: Translate wasm module bytes to `TranslatedModule` Struct [impl](https://github.com/bytecodealliance/wasmtime/blob/master/crates/lightbeam/src/module.rs#L503) 52 | 53 | - Examples: 54 | - [tests](https://github.com/bytecodealliance/wasmtime/tree/master/tests) 55 | - [examples](https://github.com/bytecodealliance/wasmtime/tree/master/examples) 56 | - [fuzzing](https://github.com/bytecodealliance/wasmtime/tree/master/fuzz) 57 | 58 |

59 |
60 | 61 | 62 | ## wasmer (Rust) 63 | 64 | Standalone WebAssembly runtime: [github](https://github.com/wasmerio/wasmer) / [documentation](https://docs.wasmer.io/) 65 | 66 | 67 |
Details 68 |

69 | 70 | - backends: 71 | - [singlepass](https://github.com/wasmerio/wasmer/tree/master/lib/singlepass-backend) 72 | - [cranelift](https://github.com/wasmerio/wasmer/tree/master/lib/clif-backend) 73 | - [LLVM](https://github.com/wasmerio/wasmer/tree/master/lib/llvm-backend) 74 | 75 | - APIs: 76 | - `wasmer_runtime::validate`: Perform validation of the wasm module - [doc](https://docs.rs/wasmer-runtime-core/0.16.2/src/wasmer_runtime_core/lib.rs.html#140-142) 77 | - `wasmer_runtime::validate_and_report_errors_with_features`: Perform validation with a Features - doc[https://docs.rs/wasmer-runtime-core/0.7.0/wasmer_runtime_core/fn.validate_and_report_errors_with_features.html] 78 | - `wasmer_runtime::{compile, compile_with}`: Compile WebAssembly binary code into a Module, backends can be specified here - [doc](https://docs.rs/wasmer-runtime/0.16.2/wasmer_runtime/fn.compile.html) 79 | - `wasmer_runtime::instantiate`: Compile and instantiate wasm code - [doc](https://docs.rs/wasmer-runtime/0.16.2/wasmer_runtime/fn.instantiate.html) 80 | 81 | - Examples: 82 | - [examples](https://github.com/wasmerio/wasmer/tree/master/examples) 83 | - [tests](https://github.com/wasmerio/wasmer/tree/master/lib/spectests) 84 | - [fuzzing](https://github.com/wasmerio/wasmer/tree/master/fuzz) 85 | - [fuzzing](https://github.com/wasmerio/wasm-fuzz) 86 | 87 |

88 |
89 | 90 | 91 | ## parity-wasm (Rust) 92 | 93 | WebAssembly serialization/deserialization in rust: [github](https://github.com/paritytech/parity-wasm) / [documentation](https://docs.rs/parity-wasm/0.41.0/parity_wasm/) 94 | 95 |
Details 96 |

97 | 98 | - APIs: 99 | - `parity_wasm::deserialize_file`: module parsing - [test](https://github.com/paritytech/parity-wasm/blob/master/src/elements/module.rs#L650-L656) 100 | - `parity_wasm::Module` struct: WebAssembly module [impl](https://github.com/paritytech/parity-wasm/blob/master/src/elements/module.rs#L48) 101 | - `parity_wasm::serialize_to_file`: will not be supported for the moment. 102 | 103 | - Examples: 104 | - [tests](https://github.com/paritytech/parity-wasm/blob/master/src/elements/module.rs#L650-L656) 105 | - [examples](https://github.com/paritytech/parity-wasm/tree/master/examples) 106 | - [fuzzing](https://github.com/paritytech/parity-wasm/blob/master/fuzz/fuzz_targets/deserialize.rs) 107 | 108 |

109 |
110 | 111 | ## wasmparser (Rust) 112 | 113 | A simple event-driven library for parsing WebAssembly binary files: [github](https://github.com/bytecodealliance/wasmparser) / [documentation](https://docs.rs/wasmparser/0.51.4/wasmparser/) 114 | 115 |
Details 116 |

117 | 118 | - APIs: 119 | - `wasmparser::Parser`: Event-driven parser of WebAssembly binary - [impl](https://github.com/bytecodealliance/wasmparser/blob/master/src/parser.rs#L212) 120 | - `wasmparser::ValidatingParser`: validate module depending of provided config - [impl](https://github.com/bytecodealliance/wasmparser/blob/master/src/validator.rs#L157) 121 | - `wasmparser::ValidatingParserConfig`: validate module depending of provided config - [impl](https://github.com/bytecodealliance/wasmparser/blob/master/src/validator.rs#L89) 122 | 123 | - Examples: 124 | - [tests](https://github.com/bytecodealliance/wasmparser/tree/master/tests) 125 | - [examples](https://github.com/bytecodealliance/wasmparser/tree/master/examples) 126 | - [fuzzing](https://github.com/bytecodealliance/wasmparser/tree/master/fuzz/fuzz_targets) 127 | 128 |

129 |
130 | 131 | ## binaryen (C++/Rust) 132 | 133 | Compiler infrastructure and toolchain: [github](https://github.com/WebAssembly/binaryen) / [rust bindings](https://github.com/pepyakin/binaryen-rs) 134 | 135 |
Details 136 |

137 | 138 | - Rust APIs: 139 | - `binaryen::Module::read`: Deserialize a module from binary form. - [impl](https://github.com/pepyakin/binaryen-rs/blob/abe2babb2d1d8e88a5f2aa47fb6e24393e19e8c0/src/lib.rs#L64) 140 | - `binaryen::Module::optimize`: Run the standard optimization passes on the module. - [impl](https://github.com/pepyakin/binaryen-rs/blob/abe2babb2d1d8e88a5f2aa47fb6e24393e19e8c0/src/lib.rs#L81) 141 | - `Binaryen` interpreter: Simple WebAssembly interpreter - [code](https://github.com/WebAssembly/binaryen/blob/master/src/wasm-interpreter.h) 142 | 143 | - Rust examples: 144 | - [examples](https://github.com/pepyakin/binaryen-rs/tree/abe2babb2d1d8e88a5f2aa47fb6e24393e19e8c0/examples) 145 | 146 |

147 |
148 | 149 | ## wabt (C++/Rust) 150 | 151 | The WebAssembly Binary Toolkit - [github](https://github.com/WebAssembly/wabt) / [rust bindings](https://github.com/pepyakin/wabt-rs) 152 | 153 |
Details 154 |

155 | 156 | - Rust Apis: 157 | - `Module`: WebAssembly module. (take a `Features` struct - possible to active `enable_all`(https://github.com/pepyakin/wabt-rs/blob/master/src/lib.rs#L182)) 158 | - `Module::read_binary` / `wasm2wat::convert`: useful if we validate the module first since `read_binary doesn't do any validation`. 159 | - `wasm2wat`: Disassemble wasm binary to wasm text format. - [doc](https://docs.rs/wabt/0.9.2/wabt/fn.wasm2wat.html) 160 | - `wasm2wat_with_features`: Disassemble wasm binary to wasm text format with the given features. - [doc](https://docs.rs/wabt/0.9.2/wabt/fn.wasm2wat_with_features.html) 161 | - `Module::validate`: Validate the module. - [impl](https://github.com/pepyakin/wabt-rs/blob/master/src/lib.rs#L731) 162 | - `wat2wasm`: Translate wasm text source to wasm binary format. - NOT A PRIORITY TO IMPLEMENT - [doc](https://docs.rs/wabt/0.9.2/wabt/fn.wat2wasm.html) 163 | - `wat2wasm_with_features`: Translate wasm text source to wasm binary format with the given features. - NOT A PRIORITY TO IMPLEMENT - [doc](https://docs.rs/wabt/0.9.2/wabt/fn.wat2wasm_with_features.html) 164 | 165 | - Rust examples: 166 | - [examples](https://github.com/pepyakin/wabt-rs/blob/a8337f520b404fc09484654a4c6653ee078ac86b/src/lib.rs#L1111) 167 | 168 |

169 |
170 | 171 | ## wasm-tools/wasmprinter (Rust) 172 | 173 | A Rust parser for printing a WebAssembly binary in the WebAssembly Text Format (WAT). - [github](https://github.com/bytecodealliance/wasm-tools/tree/master/crates/wasmprinter) 174 | 175 |
Details 176 |

177 | 178 | - Rust Apis: 179 | - `print_bytes`: Prints an in-memory wasm binary blob into an in-memory String which is its textual representation. - [doc](https://docs.rs/wasmprinter/0.2.5/wasmprinter/fn.print_bytes.html) 180 | 181 |

182 |
183 | 184 | 185 | ## wasm-tools/wat (Rust) 186 | 187 | A Rust parser for the WebAssembly Text Format (WAT). - [github](https://github.com/bytecodealliance/wasm-tools/tree/master/crates/wat) 188 | 189 |
Details 190 |

191 | 192 | - Rust Apis: 193 | - `wat::parse_str`: [doc](https://docs.rs/wat/1.0.3/wat/fn.parse_str.html) 194 | 195 |

196 |
197 | 198 | ## wasm-tools/wast (Rust) 199 | 200 | A Rust parser for the WebAssembly Text Format (WAST). - [github](https://github.com/bytecodealliance/wasm-tools/tree/master/crates/wast) 201 | 202 |
Details 203 |

204 | 205 | - Rust Apis: 206 | - `ParseBuffer::new` 207 | - `parser::parse::` 208 | 209 |

210 |
211 | 212 | ## wain (Rust) 213 | 214 | WebAssembly implementation from scratch in Safe Rust with zero dependencies - [github](https://github.com/rhysd/wain) 215 | 216 |
Details 217 |

218 | 219 | - Rust Apis: 220 | - `wain_syntax_binary::parse`: [github](https://docs.rs/wain-syntax-binary/0.1.2/wain_syntax_binary/fn.parse.html) 221 | - `wain_validate::validate`: [github](https://docs.rs/wain-validate/0.1.3/wain_validate/fn.validate.html) 222 | 223 |

224 |
225 | 226 | ## wasm3 (C++/Rust) 227 | 228 | - [wasm3](https://github.com/wasm3/wasm3) - high performance WebAssembly interpreter written in C. - [rust bindings](https://github.com/Veykril/wasm3-rs) 229 | 230 |
Details 231 |

232 | 233 | - Rust Apis: 234 | - `Module::parse` 235 | 236 |

237 |
238 | 239 | ## fizzy (C++/Rust) 240 | 241 | - [fizzy](https://github.com/wasmx/fizzy) - fast, deterministic, and pedantic WebAssembly interpreter written in C++. - [rust bindings](https://github.com/wasmx/fizzy/tree/master/bindings/rust) 242 | 243 |
Details 244 |

245 | 246 | - Rust Apis: 247 | - `fizzy::validate` - [doc](https://docs.rs/fizzy/0.6.0-dev/fizzy/fn.validate.html) 248 | 249 |

250 |
251 | 252 | # Projects potentially integrated. 253 | 254 | Those projects **will be potentially** supported/integrated in the future. 255 | 256 | - [WAVM](https://github.com/WAVM/WAVM) - WebAssembly Virtual Machine in C++. 257 | - [webassemblyjs](https://github.com/xtuc/webassemblyjs) - Toolchain for WebAssembly in JavaScript. 258 | - [wagon](https://github.com/go-interpreter/wagon) - WebAssembly-based Go interpreter, for Go. 259 | -------------------------------------------------------------------------------- /warf/targets/src/lib.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Differential fuzzing: 3 | We are checking that all those different implementation return 4 | the same thing i.e. true or false in our cases. 5 | */ 6 | 7 | pub fn fuzz_diff_parsing(data: &[u8]) { 8 | let a = parity_wasm::parity_wasm_deserialize(&data); 9 | let b = wasmer::fuzz_wasmer_compile_clif(&data); 10 | let c = wasmer::fuzz_wasmer_compile_singlepass(&data); 11 | let d = wasmtime::fuzz_wasmtime_compile_all_cranelift(&data); 12 | let e = wasmparser::fuzz_wasmparser_validate_all_feat(&data); 13 | let f = binaryen_ffi::fuzz_binaryen_ffi(&data); 14 | let g = wasmprinter::fuzz_wasmprinter_parser(&data); 15 | 16 | let _ = match (a, b, c, d, e, f, g) { 17 | (true, true, true, true, true, true, true) => true, 18 | (false, false, false, false, false, false, false) => false, 19 | _ => panic!( 20 | "fuzz_diff_parsing panic: {}-{}-{}-{}-{}-{}-{}", 21 | a, b, c, d, e, f, g 22 | ), 23 | }; 24 | } 25 | 26 | pub fn debug_diff_parsing(data: &[u8]) -> bool { 27 | let a = parity_wasm::parity_wasm_deserialize(&data); 28 | let b = wasmer::fuzz_wasmer_compile_clif(&data); 29 | let c = wasmer::fuzz_wasmer_compile_singlepass(&data); 30 | let d = wasmtime::fuzz_wasmtime_compile_all_cranelift(&data); 31 | let e = wasmparser::fuzz_wasmparser_validate_all_feat(&data); 32 | let f = binaryen_ffi::fuzz_binaryen_ffi(&data); 33 | let g = wasmprinter::fuzz_wasmprinter_parser(&data); 34 | 35 | match (a, b, c, d, e, f, g) { 36 | (true, true, true, true, true, true, true) => true, 37 | (false, false, false, false, false, false, false) => true, 38 | _ => false, 39 | } 40 | } 41 | 42 | pub fn fuzz_diff_all_validate(data: &[u8]) { 43 | let a = wasmi::wasmi_validate(&data); 44 | let b = wasmer::fuzz_wasmer_validate(&data); 45 | let c = wasmtime::fuzz_wasmtime_validate_all_feat(&data); 46 | let d = wasmparser::fuzz_wasmparser_validate_all_feat(&data); 47 | let e = wabt_ffi::fuzz_wabt_validate_ffi(&data); 48 | let f = fizzy::fizzy_validate(&data); 49 | 50 | let _ = match (a, b, c, d, e, f) { 51 | (true, true, true, true, true, true) => true, 52 | (false, false, false, false, false, false) => false, 53 | _ => panic!( 54 | "fuzz_diff_all_validate panic: {}-{}-{}-{}-{}-{}", 55 | a, b, c, d, e, f 56 | ), 57 | }; 58 | } 59 | 60 | pub fn debug_diff_all_validate(data: &[u8]) -> bool { 61 | let a = wasmi::wasmi_validate(&data); 62 | let b = wasmer::fuzz_wasmer_validate(&data); 63 | let c = wasmtime::fuzz_wasmtime_validate_all_feat(&data); 64 | let d = wasmparser::fuzz_wasmparser_validate_all_feat(&data); 65 | let e = wabt_ffi::fuzz_wabt_validate_ffi(&data); 66 | let f = fizzy::fizzy_validate(&data); 67 | 68 | match (a, b, c, d, e, f) { 69 | (true, true, true, true, true, true) => true, 70 | (false, false, false, false, false, false) => true, 71 | _ => false, 72 | } 73 | } 74 | 75 | pub fn fuzz_diff_instantiate(data: &[u8]) { 76 | let a = wasmi::wasmi_instantiate(&data); 77 | let b = wasmer::fuzz_wasmer_instantiate(&data); 78 | let c = wasmtime::fuzz_wasmtime_instantiate_all_cranelift(&data); 79 | let _ = match (a, b, c) { 80 | (true, true, true) => true, 81 | (false, false, false) => false, 82 | _ => panic!("fuzz_diff_instantiate panic: {}-{}-{}", a, b, c), 83 | }; 84 | } 85 | 86 | pub fn debug_diff_instantiate(data: &[u8]) -> bool { 87 | let a = wasmi::wasmi_instantiate(&data); 88 | let b = wasmer::fuzz_wasmer_instantiate(&data); 89 | let c = wasmtime::fuzz_wasmtime_instantiate_all_cranelift(&data); 90 | match (a, b, c) { 91 | (true, true, true) => true, 92 | (false, false, false) => true, 93 | _ => false, 94 | } 95 | } 96 | 97 | pub fn fuzz_diff_wat_parsing(data: &[u8]) { 98 | let a = wabt_ffi::fuzz_wabt_wat2wasm_ffi(&data); 99 | let b = wat::wat_parser(&data); 100 | let _ = match (a, b) { 101 | (true, true) => true, 102 | (false, false) => false, 103 | _ => panic!("fuzz_diff_wat_parsing panic: {}-{}", a, b), 104 | }; 105 | } 106 | 107 | pub fn debug_diff_wat_parsing(data: &[u8]) -> bool { 108 | let a = wabt_ffi::fuzz_wabt_wat2wasm_ffi(&data); 109 | let b = wat::wat_parser(&data); 110 | match (a, b) { 111 | (true, true) => true, 112 | (false, false) => true, 113 | _ => false, 114 | } 115 | } 116 | 117 | mod wasmi; 118 | // fuzzing harnesses 119 | pub fn fuzz_wasmi_validate(data: &[u8]) { 120 | let _ = wasmi::wasmi_validate(&data); 121 | } 122 | pub fn fuzz_wasmi_instantiate(data: &[u8]) { 123 | let _ = wasmi::wasmi_instantiate(&data); 124 | } 125 | // debug target 126 | pub fn debug_wasmi_validate(data: &[u8]) -> bool { 127 | wasmi::wasmi_validate(&data) 128 | } 129 | pub fn debug_wasmi_instantiate(data: &[u8]) -> bool { 130 | wasmi::wasmi_instantiate(&data) 131 | } 132 | 133 | mod parity_wasm; 134 | // fuzzing harnesses 135 | pub fn fuzz_parity_wasm_deserialize(data: &[u8]) { 136 | let _ = parity_wasm::parity_wasm_deserialize(&data); 137 | } 138 | // debug target 139 | pub fn debug_parity_wasm_deserialize(data: &[u8]) -> bool { 140 | parity_wasm::parity_wasm_deserialize(&data) 141 | } 142 | 143 | mod wasmer; 144 | // fuzzing harnesses 145 | pub fn fuzz_wasmer_validate(data: &[u8]) { 146 | let _ = wasmer::fuzz_wasmer_validate(&data); 147 | } 148 | pub fn fuzz_wasmer_compile_clif(data: &[u8]) { 149 | let _ = wasmer::fuzz_wasmer_compile_clif(&data); 150 | } 151 | pub fn fuzz_wasmer_compile_singlepass(data: &[u8]) { 152 | let _ = wasmer::fuzz_wasmer_compile_singlepass(&data); 153 | } 154 | pub fn fuzz_wasmer_instantiate(data: &[u8]) { 155 | let _ = wasmer::fuzz_wasmer_instantiate(&data); 156 | } 157 | // debug target 158 | pub fn debug_wasmer_validate(data: &[u8]) -> bool { 159 | wasmer::fuzz_wasmer_validate(&data) 160 | } 161 | pub fn debug_wasmer_compile_clif(data: &[u8]) -> bool { 162 | wasmer::fuzz_wasmer_compile_clif(&data) 163 | } 164 | pub fn debug_wasmer_compile_singlepass(data: &[u8]) -> bool { 165 | wasmer::fuzz_wasmer_compile_singlepass(&data) 166 | } 167 | pub fn debug_wasmer_instantiate(data: &[u8]) -> bool { 168 | wasmer::fuzz_wasmer_instantiate(&data) 169 | } 170 | 171 | mod wasmtime; 172 | // fuzzing harnesses 173 | pub fn fuzz_wasmtime_validate(data: &[u8]) { 174 | let _ = wasmtime::fuzz_wasmtime_validate(&data); 175 | } 176 | pub fn fuzz_wasmtime_validate_all_feat(data: &[u8]) { 177 | let _ = wasmtime::fuzz_wasmtime_validate_all_feat(&data); 178 | } 179 | pub fn fuzz_wasmtime_compile(data: &[u8]) { 180 | let _ = wasmtime::fuzz_wasmtime_compile(&data); 181 | } 182 | pub fn fuzz_wasmtime_compile_all_cranelift(data: &[u8]) { 183 | let _ = wasmtime::fuzz_wasmtime_compile_all_cranelift(&data); 184 | } 185 | /* DEACTIVATED FOR NOW 186 | pub fn _fuzz_wasmtime_compile_all_lightbeam(data: &[u8]) { 187 | let _ = wasmtime::fuzz_wasmtime_compile_all_lightbeam(data); 188 | } 189 | */ 190 | pub fn fuzz_wasmtime_instantiate_all_cranelift(data: &[u8]) { 191 | let _ = wasmtime::fuzz_wasmtime_instantiate_all_cranelift(&data); 192 | } 193 | /* DEACTIVATED FOR NOW 194 | pub fn _fuzz_wasmtime_instantiate_all_lightbeam(data: &[u8]) { 195 | let _ = wasmtime::fuzz_wasmtime_instantiate_all_lightbeam(data); 196 | } 197 | */ 198 | // debug target 199 | pub fn debug_wasmtime_validate(data: &[u8]) -> bool { 200 | wasmtime::fuzz_wasmtime_validate(&data) 201 | } 202 | pub fn debug_wasmtime_validate_all_feat(data: &[u8]) -> bool { 203 | wasmtime::fuzz_wasmtime_validate_all_feat(&data) 204 | } 205 | pub fn debug_wasmtime_compile(data: &[u8]) -> bool { 206 | wasmtime::fuzz_wasmtime_compile(&data) 207 | } 208 | pub fn debug_wasmtime_compile_all_cranelift(data: &[u8]) -> bool { 209 | wasmtime::fuzz_wasmtime_compile_all_cranelift(&data) 210 | } 211 | /* DEACTIVATED FOR NOW 212 | pub fn _debug_wasmtime_compile_all_lightbeam(data: &[u8]) -> bool { 213 | wasmtime::fuzz_wasmtime_compile_all_lightbeam(data) 214 | } 215 | */ 216 | pub fn debug_wasmtime_instantiate_all_cranelift(data: &[u8]) -> bool { 217 | wasmtime::fuzz_wasmtime_instantiate_all_cranelift(&data) 218 | } 219 | /* DEACTIVATED FOR NOW 220 | pub fn _debug_wasmtime_instantiate_all_lightbeam(data: &[u8]) -> bool { 221 | wasmtime::fuzz_wasmtime_instantiate_all_lightbeam(data) 222 | } 223 | 224 | mod lightbeam; 225 | // fuzzing harnesses 226 | pub fn _fuzz_lightbeam_translate(data: &[u8]) { 227 | let _ = lightbeam::fuzz_lightbeam_translate(data); 228 | } 229 | // debug target 230 | pub fn _debug_lightbeam_translate(data: &[u8]) -> bool { 231 | lightbeam::fuzz_lightbeam_translate(data) 232 | } 233 | */ 234 | 235 | mod wasmparser; 236 | // fuzzing harnesses 237 | pub fn fuzz_wasmparser_parser(data: &[u8]) { 238 | let _ = wasmparser::fuzz_wasmparser_parser(&data); 239 | } 240 | pub fn fuzz_wasmparser_validate(data: &[u8]) { 241 | let _ = wasmparser::fuzz_wasmparser_validate(&data); 242 | } 243 | pub fn fuzz_wasmparser_validate_all_feat(data: &[u8]) { 244 | let _ = wasmparser::fuzz_wasmparser_validate_all_feat(&data); 245 | } 246 | // debug target 247 | pub fn debug_wasmparser_parser(data: &[u8]) -> bool { 248 | wasmparser::fuzz_wasmparser_parser(&data) 249 | } 250 | pub fn debug_wasmparser_validate(data: &[u8]) -> bool { 251 | wasmparser::fuzz_wasmparser_validate(&data) 252 | } 253 | pub fn debug_wasmparser_validate_all_feat(data: &[u8]) -> bool { 254 | wasmparser::fuzz_wasmparser_validate_all_feat(&data) 255 | } 256 | 257 | mod binaryen_ffi; 258 | // fuzzing harnesses 259 | pub fn fuzz_binaryen_ffi(data: &[u8]) { 260 | let _ = binaryen_ffi::fuzz_binaryen_ffi(&data); 261 | } 262 | pub fn fuzz_binaryen_optimize_ffi(data: &[u8]) { 263 | let _ = binaryen_ffi::fuzz_binaryen_optimize_ffi(&data); 264 | } 265 | // debug target 266 | pub fn debug_binaryen_ffi(data: &[u8]) -> bool { 267 | binaryen_ffi::fuzz_binaryen_ffi(&data) 268 | } 269 | pub fn debug_binaryen_optimize_ffi(data: &[u8]) -> bool { 270 | binaryen_ffi::fuzz_binaryen_optimize_ffi(&data) 271 | } 272 | 273 | mod wabt_ffi; 274 | 275 | pub fn fuzz_wabt_wasm2wat_all_feat_ffi(data: &[u8]) { 276 | let _ = wabt_ffi::fuzz_wabt_wasm2wat_all_feat_ffi(&data); 277 | } 278 | pub fn fuzz_wabt_validate_ffi(data: &[u8]) { 279 | let _ = wabt_ffi::fuzz_wabt_validate_ffi(&data); 280 | } 281 | pub fn fuzz_wabt_wat2wasm_ffi(data: &[u8]) { 282 | let _ = wabt_ffi::fuzz_wabt_wat2wasm_ffi(&data); 283 | } 284 | 285 | // debug target 286 | pub fn debug_wabt_wasm2wat_all_feat_ffi(data: &[u8]) -> bool { 287 | wabt_ffi::fuzz_wabt_wasm2wat_all_feat_ffi(&data) 288 | } 289 | pub fn debug_wabt_validate_ffi(data: &[u8]) -> bool { 290 | wabt_ffi::fuzz_wabt_validate_ffi(&data) 291 | } 292 | pub fn debug_wabt_wat2wasm_ffi(data: &[u8]) -> bool { 293 | wabt_ffi::fuzz_wabt_wat2wasm_ffi(&data) 294 | } 295 | 296 | mod wasm3; 297 | pub fn fuzz_wasm3_parser_ffi(data: &[u8]) { 298 | let _ = wasm3::fuzz_wasm3_parser_ffi(&data); 299 | } 300 | pub fn debug_wasm3_parser_ffi(data: &[u8]) -> bool { 301 | wasm3::fuzz_wasm3_parser_ffi(&data) 302 | } 303 | 304 | mod wasmprinter; 305 | pub fn fuzz_wasmprinter_parser(data: &[u8]) { 306 | let _ = wasmprinter::fuzz_wasmprinter_parser(&data); 307 | } 308 | 309 | pub fn debug_wasmprinter_parser(data: &[u8]) -> bool { 310 | wasmprinter::fuzz_wasmprinter_parser(&data) 311 | } 312 | 313 | mod wain; 314 | pub fn fuzz_wain_parser(data: &[u8]) { 315 | let _ = wain::fuzz_wain_parser(&data); 316 | } 317 | pub fn fuzz_wain_validate(data: &[u8]) { 318 | let _ = wain::fuzz_wain_validate(&data); 319 | } 320 | 321 | pub fn debug_wain_parser(data: &[u8]) -> bool { 322 | wain::fuzz_wain_parser(&data) 323 | } 324 | pub fn debug_wain_validate(data: &[u8]) -> bool { 325 | wain::fuzz_wain_validate(&data) 326 | } 327 | 328 | mod wat; 329 | pub fn fuzz_wat_parser(data: &[u8]) { 330 | let _ = wat::wat_parser(&data); 331 | } 332 | pub fn debug_wat_parser(data: &[u8]) -> bool { 333 | wat::wat_parser(&data) 334 | } 335 | 336 | mod wast; 337 | pub fn fuzz_wast_parser(data: &[u8]) { 338 | let _ = wast::wast_parser(&data); 339 | } 340 | pub fn debug_wast_parser(data: &[u8]) -> bool { 341 | wast::wast_parser(&data) 342 | } 343 | 344 | mod fizzy; 345 | pub fn fuzz_fizzy_validate(data: &[u8]) { 346 | let _ = fizzy::fizzy_validate(&data); 347 | } 348 | pub fn debug_fizzy_validate(data: &[u8]) -> bool { 349 | fizzy::fizzy_validate(&data) 350 | } 351 | -------------------------------------------------------------------------------- /warf/src/rust_fuzzers.rs: -------------------------------------------------------------------------------- 1 | use failure::{Error, ResultExt}; 2 | use std::env; 3 | use std::ffi::OsStr; 4 | use std::fs; 5 | use std::path::PathBuf; 6 | use std::process::Command; 7 | use strum::IntoEnumIterator; 8 | 9 | use crate::env::{corpora_dir, root_dir}; 10 | use crate::fuzzers::{write_fuzzer_target, FuzzerConfig, FuzzerQuit}; 11 | use crate::targets::{prepare_targets_workspace, Targets}; 12 | use crate::utils::copy_dir; 13 | 14 | /*********************************************** 15 | name: honggfuzz-rs 16 | github: https://github.com/rust-fuzz/honggfuzz-rs 17 | ***********************************************/ 18 | 19 | pub struct FuzzerHfuzz { 20 | /// Fuzzer name. 21 | pub name: String, 22 | /// Source code / template dir 23 | pub dir: PathBuf, 24 | /// Workspace dir 25 | pub work_dir: PathBuf, 26 | /// Internal workspace dir 27 | pub workspace_dir: PathBuf, 28 | /// fuzzing config 29 | pub config: FuzzerConfig, 30 | } 31 | 32 | impl FuzzerHfuzz { 33 | /// Check if `cargo hfuzz` is installed 34 | pub fn is_available() -> Result<(), Error> { 35 | let fuzzer_output = Command::new("cargo").arg("hfuzz").arg("version").output()?; 36 | if !fuzzer_output.status.success() { 37 | bail!("hfuzz not available, install with `cargo install honggfuzz`"); 38 | } 39 | Ok(()) 40 | } 41 | 42 | /// Create a new FuzzerHfuzz 43 | pub fn new(config: FuzzerConfig) -> Result { 44 | // Test if fuzzer engine installed 45 | FuzzerHfuzz::is_available()?; 46 | 47 | let cwd = env::current_dir().context("error getting current directory")?; 48 | let fuzzer = FuzzerHfuzz { 49 | name: "Honggfuzz".to_string(), 50 | dir: cwd.join("fuzzers").join("rust-honggfuzz"), 51 | work_dir: cwd.join("workspace").join("hfuzz"), 52 | workspace_dir: cwd.join("workspace").join("hfuzz").join("hfuzz_workspace"), 53 | config, 54 | }; 55 | Ok(fuzzer) 56 | } 57 | 58 | // TODO - simplify this function 59 | fn prepare_fuzzer_workspace(&self) -> Result<(), Error> { 60 | let hfuzz_dir = &self.work_dir; 61 | fs::create_dir_all(&hfuzz_dir) 62 | .context(format!("unable to create {} dir", hfuzz_dir.display()))?; 63 | 64 | let src_dir = hfuzz_dir.join("src"); 65 | fs::create_dir_all(&src_dir) 66 | .context(format!("unable to create {} dir", src_dir.display()))?; 67 | 68 | fs::copy(self.dir.join("Cargo.toml"), hfuzz_dir.join("Cargo.toml"))?; 69 | fs::copy(self.dir.join("template.rs"), hfuzz_dir.join("template.rs"))?; 70 | fs::copy(self.dir.join("src").join("lib.rs"), src_dir.join("lib.rs"))?; 71 | Ok(()) 72 | } 73 | 74 | pub fn run(&self, target: Targets) -> Result<(), Error> { 75 | // check if target is supported by this fuzzer 76 | // TODO - change to make it automatic 77 | if target.language() != "rust" { 78 | bail!("FuzzerHfuzz incompatible for this target"); 79 | } 80 | 81 | // get path to corpora 82 | let corpora_dir = corpora_dir()?.join(target.corpora()); 83 | 84 | // copy targets folder into workspace 85 | prepare_targets_workspace()?; 86 | 87 | // create hfuzz folder inside workspace/ 88 | self.prepare_fuzzer_workspace()?; 89 | 90 | // write all fuzz targets inside hfuzz folder 91 | write_fuzzer_target(&self.dir, &self.work_dir, target)?; 92 | println!("[WARF] {}: {} created", self.name, target.name()); 93 | 94 | // sanitizers 95 | let rust_args = format!( 96 | "{} \ 97 | {}", 98 | if let Some(san) = self.config.sanitizer { 99 | format!("-Z sanitizer={}", san.name()) 100 | } else { 101 | "".into() 102 | }, 103 | env::var("RUSTFLAGS").unwrap_or_default() 104 | ); 105 | 106 | // Handle seed option 107 | if self.config.seed != None { 108 | println!("[WARF] {}: seed not supported", self.name); 109 | } 110 | 111 | // prepare arguments 112 | let hfuzz_args = format!( 113 | "{} \ 114 | {} \ 115 | {} \ 116 | {} \ 117 | {}", 118 | if let Some(t) = self.config.timeout { 119 | format!("--run_time {}", t) 120 | } else { 121 | "".into() 122 | }, 123 | "-t 2", 124 | // Set number of thread 125 | if let Some(n) = self.config.thread { 126 | format!("--threads {}", n) 127 | } else { 128 | "".into() 129 | }, 130 | // set the dictionnary 131 | if let Some(dict) = self.config.dict.clone() { 132 | format!("--dict {}", root_dir()?.join(dict).display()) 133 | } else { 134 | "".into() 135 | }, 136 | env::var("HFUZZ_RUN_ARGS").unwrap_or_default() 137 | ); 138 | 139 | // Honggfuzz will first build than run the fuzzer using cargo 140 | let fuzzer_bin = Command::new("cargo") // , 141 | .args(&["+nightly", "hfuzz", "run", &target.name()]) 142 | .env("RUSTFLAGS", &rust_args) 143 | .env("HFUZZ_RUN_ARGS", &hfuzz_args) 144 | //.env("HFUZZ_BUILD_ARGS", "opt-level=3") 145 | .env("HFUZZ_INPUT", corpora_dir) 146 | .current_dir(&self.work_dir) 147 | .spawn() 148 | .context(format!( 149 | "error starting {} to run {}", 150 | self.name, 151 | target.name() 152 | ))? 153 | .wait() 154 | .context(format!( 155 | "error while waiting for {} running {}", 156 | self.name, 157 | target.name() 158 | ))?; 159 | 160 | if !fuzzer_bin.success() { 161 | return Err(FuzzerQuit.into()); 162 | } 163 | Ok(()) 164 | } 165 | } 166 | 167 | /*********************************************** 168 | name: afl-rs 169 | github: https://github.com/rust-fuzz/afl.rs 170 | ***********************************************/ 171 | 172 | pub struct FuzzerAfl { 173 | /// Fuzzer name. 174 | pub name: String, 175 | /// Source code / template dir 176 | pub dir: PathBuf, 177 | /// Workspace dir 178 | pub work_dir: PathBuf, 179 | /// Internal workspace dir 180 | pub workspace_dir: PathBuf, 181 | /// fuzzing config 182 | pub config: FuzzerConfig, 183 | } 184 | 185 | impl FuzzerAfl { 186 | /// Check if `cargo afl` is installed 187 | pub fn is_available() -> Result<(), Error> { 188 | let fuzzer_output = Command::new("cargo").arg("afl").arg("--version").output()?; 189 | if !fuzzer_output.status.success() { 190 | bail!("afl-rs not available, install with `cargo install afl`"); 191 | } 192 | Ok(()) 193 | } 194 | 195 | /// Create a new FuzzerAfl 196 | pub fn new(config: FuzzerConfig) -> Result { 197 | // Test if fuzzer engine installed 198 | FuzzerAfl::is_available()?; 199 | 200 | let cwd = env::current_dir().context("error getting current directory")?; 201 | let fuzzer = FuzzerAfl { 202 | name: "Afl++".to_string(), 203 | dir: cwd.join("fuzzers").join("rust-afl"), 204 | work_dir: cwd.join("workspace").join("afl"), 205 | workspace_dir: cwd.join("workspace").join("afl").join("afl_workspace"), 206 | config, 207 | }; 208 | Ok(fuzzer) 209 | } 210 | 211 | // TODO - simplify that 212 | fn prepare_fuzzer_workspace(&self) -> Result<(), Error> { 213 | let hfuzz_dir = &self.work_dir; 214 | fs::create_dir_all(&hfuzz_dir) 215 | .context(format!("unable to create {} dir", hfuzz_dir.display()))?; 216 | 217 | let src_dir = hfuzz_dir.join("src"); 218 | fs::create_dir_all(&src_dir) 219 | .context(format!("unable to create {} dir", src_dir.display()))?; 220 | 221 | fs::copy(self.dir.join("Cargo.toml"), hfuzz_dir.join("Cargo.toml"))?; 222 | fs::copy(self.dir.join("template.rs"), hfuzz_dir.join("template.rs"))?; 223 | fs::copy(self.dir.join("src").join("lib.rs"), src_dir.join("lib.rs"))?; 224 | Ok(()) 225 | } 226 | 227 | /// Build single target with afl 228 | pub fn build_afl(&self, target: Targets) -> Result<(), Error> { 229 | prepare_targets_workspace()?; 230 | // create afl folder inside workspace/ 231 | self.prepare_fuzzer_workspace()?; 232 | 233 | write_fuzzer_target(&self.dir, &self.work_dir, target)?; 234 | 235 | // sanitizers 236 | let rust_args = format!( 237 | "{} \ 238 | {}", 239 | if let Some(san) = self.config.sanitizer { 240 | format!("-Z sanitizer={}", san.name()) 241 | } else { 242 | "".into() 243 | }, 244 | env::var("RUSTFLAGS").unwrap_or_default() 245 | ); 246 | 247 | let build_cmd = Command::new("cargo") // "+nightly", 248 | .args(&["afl", "build", "--bin", &target.name()]) // TODO: not sure we want to compile afl in "--release" 249 | .env("RUSTFLAGS", &rust_args) 250 | .current_dir(&self.work_dir) 251 | .spawn() 252 | .context(format!( 253 | "error starting build for {} of {}", 254 | self.name, 255 | target.name() 256 | ))? 257 | .wait() 258 | .context(format!( 259 | "error while waiting for build for {} of {}", 260 | self.name, 261 | target.name() 262 | ))?; 263 | 264 | if !build_cmd.success() { 265 | return Err(FuzzerQuit.into()); 266 | } 267 | 268 | Ok(()) 269 | } 270 | 271 | pub fn run(&self, target: Targets) -> Result<(), Error> { 272 | // check if target is supported by this fuzzer 273 | // TODO - change to make it automatic 274 | if target.language() != "rust" { 275 | bail!("FuzzerAfl incompatible for this target"); 276 | } 277 | 278 | let dir = &self.work_dir; 279 | let corpora_dir = corpora_dir()?.join(target.corpora()); 280 | 281 | self.build_afl(target)?; 282 | 283 | // TODO - modify to use same corpus than other fuzzer 284 | let corpus_dir = &self.workspace_dir; 285 | fs::create_dir_all(&corpus_dir) 286 | .context(format!("unable to create {} dir", corpus_dir.display()))?; 287 | 288 | // Determined if existing fuzzing session exist 289 | let queue_dir = corpus_dir.join("queue"); 290 | let input_arg: &OsStr = if queue_dir.is_dir() && fs::read_dir(queue_dir)?.next().is_some() { 291 | "-".as_ref() 292 | } else { 293 | corpora_dir.as_ref() 294 | }; 295 | 296 | let mut args: Vec = Vec::new(); 297 | //args.push("+nightly".to_string()); 298 | args.push("afl".to_string()); 299 | args.push("fuzz".to_string()); 300 | if let Some(t) = self.config.timeout { 301 | args.push(format!("-V {}", t)); 302 | }; 303 | if let Some(seed) = self.config.seed { 304 | args.push(format!("-s {}", seed)); 305 | }; 306 | // handle dict option 307 | if let Some(dict) = self.config.dict.clone() { 308 | args.push(format!("-x {}", root_dir()?.join(dict).display())); 309 | }; 310 | // Run the fuzzer using cargo 311 | let fuzzer_bin = Command::new("cargo") 312 | .args(args) 313 | //.arg("-t 30000+" ) // increase timeout to let the fuzzer pick a valid beaconstate 314 | .arg("-m") // remove memory limit 315 | .arg("none") 316 | .arg("-i") 317 | .arg(&input_arg) 318 | .arg("-o") 319 | .arg(&corpus_dir) 320 | .args(&["--", &format!("./target/debug/{}", target.name())]) 321 | // env variable to skip afl checking 322 | .env("AFL_SKIP_CPUFREQ", "1") 323 | .env("AFL_SKIP_CRASHES", "1") 324 | .env("AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES", "1") 325 | .current_dir(&dir) 326 | .spawn() 327 | .context(format!( 328 | "error starting {:?} to run {}", 329 | self.name, 330 | target.name() 331 | ))? 332 | .wait() 333 | .context(format!( 334 | "error while waiting for {:?} running {}", 335 | self.name, 336 | target.name() 337 | ))?; 338 | 339 | if !fuzzer_bin.success() { 340 | return Err(FuzzerQuit.into()); 341 | } 342 | Ok(()) 343 | } 344 | } 345 | 346 | /*********************************************** 347 | name: libfuzzer/cargo-fuzz 348 | github: https://github.com/rust-fuzz/cargo-fuzz 349 | ***********************************************/ 350 | 351 | pub struct FuzzerLibfuzzer { 352 | /// Fuzzer name. 353 | pub name: String, 354 | /// Source code / template dir 355 | pub dir: PathBuf, 356 | /// Workspace dir 357 | pub work_dir: PathBuf, 358 | /// Internal workspace dir 359 | pub workspace_dir: PathBuf, 360 | /// fuzzing config 361 | pub config: FuzzerConfig, 362 | } 363 | 364 | impl FuzzerLibfuzzer { 365 | /// Check if `cargo fuzz` is installed 366 | pub fn is_available() -> Result<(), Error> { 367 | let fuzzer_output = Command::new("cargo") 368 | .arg("fuzz") 369 | .arg("--version") 370 | .output()?; 371 | if !fuzzer_output.status.success() { 372 | bail!("cargo-fuzz not available, install with `cargo install cargo-fuzz`"); 373 | } 374 | Ok(()) 375 | } 376 | 377 | /// Create a new FuzzerLibfuzzer 378 | pub fn new(config: FuzzerConfig) -> Result { 379 | // Test if fuzzer engine installed 380 | FuzzerLibfuzzer::is_available()?; 381 | 382 | let cwd = env::current_dir().context("error getting current directory")?; 383 | let fuzzer = FuzzerLibfuzzer { 384 | name: "Libfuzzer".to_string(), 385 | dir: cwd.join("fuzzers").join("rust-libfuzzer"), 386 | work_dir: cwd.join("workspace").join("libfuzzer"), 387 | workspace_dir: cwd 388 | .join("workspace") 389 | .join("libfuzzer") 390 | .join("libfuzzer_workspace"), 391 | config, 392 | }; 393 | Ok(fuzzer) 394 | } 395 | 396 | fn prepare_fuzzer_workspace(&self) -> Result<(), Error> { 397 | let from = &self.dir; 398 | let workspace = &self.work_dir; 399 | copy_dir(from.to_path_buf(), workspace.to_path_buf())?; 400 | Ok(()) 401 | } 402 | 403 | pub fn run(&self, target: Targets) -> Result<(), Error> { 404 | // check if target is supported by this fuzzer 405 | // TODO - change to make it automatic 406 | if target.language() != "rust" { 407 | bail!("FuzzerLibfuzzer incompatible for this target"); 408 | } 409 | 410 | prepare_targets_workspace()?; 411 | // create afl folder inside workspace/ 412 | self.prepare_fuzzer_workspace()?; 413 | 414 | let fuzz_dir = self.work_dir.join("fuzz"); 415 | fs::create_dir_all(&fuzz_dir) 416 | .context(format!("unable to create {} dir", fuzz_dir.display()))?; 417 | 418 | let target_dir = fuzz_dir.join("fuzz_targets"); 419 | 420 | let _ = fs::remove_dir_all(&target_dir) 421 | .context(format!("error removing {}", target_dir.display())); 422 | fs::create_dir_all(&target_dir) 423 | .context(format!("unable to create {} dir", target_dir.display()))?; 424 | 425 | fs::create_dir_all(&fuzz_dir) 426 | .context(format!("unable to create {} dir", fuzz_dir.display()))?; 427 | //println!("{:?}", fuzz_dir); 428 | 429 | fs::copy( 430 | self.dir.join("fuzz").join("Cargo.toml"), 431 | fuzz_dir.join("Cargo.toml"), 432 | )?; 433 | 434 | // Add all targets to libfuzzer 435 | for target in Targets::iter().filter(|x| x.language() == "rust") { 436 | write_libfuzzer_target(&self.work_dir, target)?; 437 | } 438 | 439 | let fuzz_dir = self.work_dir.join("fuzz"); 440 | let corpus_dir = corpora_dir()?.join(target.corpora()); 441 | 442 | // sanitizers 443 | let rust_args = format!( 444 | "{} \ 445 | {}", 446 | if let Some(san) = self.config.sanitizer { 447 | format!("-Z sanitizer={}", san.name()) 448 | } else { 449 | "".into() 450 | }, 451 | env::var("RUSTFLAGS").unwrap_or_default() 452 | ); 453 | 454 | // create arguments 455 | // corpora dir 456 | // max_time if provided (i.e. continuously fuzzing) 457 | let mut args: Vec = Vec::new(); 458 | args.push(format!("{}", &corpus_dir.display())); 459 | if let Some(timeout) = self.config.timeout { 460 | args.push("--".to_string()); 461 | args.push(format!("-max_total_time={}", timeout)); 462 | }; 463 | // threading 464 | if let Some(thread) = self.config.thread { 465 | args.push(format!("-workers={}", thread)); 466 | args.push(format!("-jobs={}", thread)); 467 | }; 468 | // handle seed option 469 | if let Some(seed) = self.config.seed { 470 | args.push(format!("-seed={}", seed)); 471 | }; 472 | // handle dict option 473 | if let Some(dict) = self.config.dict.clone() { 474 | args.push(format!("-dict={}", root_dir()?.join(dict).display())); 475 | }; 476 | // Launch the fuzzer using cargo 477 | let fuzzer_bin = Command::new("cargo") // "+nightly", 478 | .args(&["fuzz", "run", &target.name()]) 479 | .args(&args) 480 | .env("RUSTFLAGS", &rust_args) 481 | .current_dir(&fuzz_dir) 482 | .spawn() 483 | .context(format!( 484 | "error starting {:?} to run {}", 485 | self.name, 486 | target.name() 487 | ))? 488 | .wait() 489 | .context(format!( 490 | "error while waiting for {:?} running {}", 491 | self.name, 492 | target.name() 493 | ))?; 494 | 495 | if !fuzzer_bin.success() { 496 | return Err(FuzzerQuit.into()); 497 | } 498 | Ok(()) 499 | } 500 | } 501 | 502 | /// Add new target for libfuzzer using `cargo fuzz add` 503 | fn write_libfuzzer_target(fuzzer_dir: &PathBuf, target: Targets) -> Result<(), Error> { 504 | use std::io::Write; 505 | 506 | let fuzz_dir = fuzzer_dir.join("fuzz"); 507 | let template_path = fuzzer_dir.join(target.template()); 508 | 509 | let template = fs::read_to_string(&template_path).context(format!( 510 | "error reading template file {}", 511 | template_path.display() 512 | ))?; 513 | 514 | // use `cargo fuzz add` to add new bin inside Cargo.toml 515 | // and create fuzz_targets dir 516 | // and create target.rs 517 | let _ = Command::new("cargo") // "+nightly", 518 | .args(&["fuzz", "add", &target.name()]) 519 | .current_dir(&fuzzer_dir) 520 | .spawn() 521 | .context(format!("error adding {}", target.name()))? 522 | .wait() 523 | .context(format!("error while adding {}", target.name())); 524 | 525 | let target_dir = fuzz_dir.join("fuzz_targets"); 526 | 527 | let path = target_dir.join(&format!("{}.rs", target.name())); 528 | 529 | let mut file = fs::OpenOptions::new() 530 | .write(true) 531 | .create(true) 532 | .truncate(true) 533 | .open(&path) 534 | .context(format!( 535 | "write_libfuzzer_target error writing fuzz target binary {}", 536 | path.display() 537 | ))?; 538 | 539 | let source = template.replace("###TARGET###", &target.name()); 540 | file.write_all(source.as_bytes())?; 541 | Ok(()) 542 | } 543 | --------------------------------------------------------------------------------