From 2ac7b6408cf6ee5022fccc102210c8ef0b164796 Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Wed, 3 Apr 2019 16:52:37 -0700 Subject: [PATCH 1/2] add validate subcommand --- src/bin/wasmer.rs | 57 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/src/bin/wasmer.rs b/src/bin/wasmer.rs index 61bd50dacc9..f29f3e63484 100644 --- a/src/bin/wasmer.rs +++ b/src/bin/wasmer.rs @@ -28,6 +28,10 @@ enum CLIOptions { #[structopt(name = "cache")] Cache(Cache), + /// Validate a Web Assembly binary + #[structopt(name = "validate")] + Validate(Validate), + /// Update wasmer to the latest version #[structopt(name = "self-update")] SelfUpdate, @@ -63,6 +67,13 @@ enum Cache { Dir, } +#[derive(Debug, StructOpt)] +struct Validate { + /// Input file + #[structopt(parse(from_os_str))] + path: PathBuf, +} + /// Read the contents of a file fn read_file_contents(path: &PathBuf) -> Result, io::Error> { let mut buffer: Vec = Vec::new(); @@ -240,6 +251,49 @@ fn run(options: Run) { } } +fn validate_wasm(validate: Validate) -> Result<(), String> { + let wasm_path = validate.path; + let wasm_path_as_str = wasm_path.to_str().unwrap(); + + let wasm_binary: Vec = read_file_contents(&wasm_path).map_err(|err| { + format!( + "Can't read the file {}: {}", + wasm_path.as_os_str().to_string_lossy(), + err + ) + })?; + + if !utils::is_wasm_binary(&wasm_binary) { + return Err(format!( + "Cannot recognize \"{}\" as a WASM binary", + wasm_path_as_str, + )); + } + + wabt::Module::read_binary(wasm_binary, &Default::default()) + .map_err(|err| { + format!( + "Failed to read \"{}\" as a WASM binary: {}", + wasm_path_as_str, err + ) + })? + .validate() + .map_err(|err| format!("Failed to validate \"{}\": {}", wasm_path_as_str, err))?; + + Ok(()) +} + +/// Runs logic for the `validate` subcommand +fn validate(validate: Validate) { + match validate_wasm(validate) { + Err(message) => { + eprintln!("Error: {}", message); + exit(-1); + } + _ => (), + } +} + fn main() { let options = CLIOptions::from_args(); match options { @@ -264,6 +318,9 @@ fn main() { println!("{}", get_cache_dir().to_string_lossy()); } }, + CLIOptions::Validate(validate_options) => { + validate(validate_options); + } #[cfg(target_os = "windows")] CLIOptions::Cache(_) => { println!("Caching is disabled for Windows."); From bda5b19098430d943f3304ac06ba11827b642027 Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Wed, 3 Apr 2019 17:21:57 -0700 Subject: [PATCH 2/2] update wasm-parser dep; use it for validation --- Cargo.lock | 8 +++++++- lib/runtime-core/Cargo.toml | 2 +- lib/runtime-core/src/lib.rs | 9 +++++++-- lib/runtime-core/src/module.rs | 2 +- src/bin/wasmer.rs | 13 +++---------- 5 files changed, 19 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 732daab18fc..f2dc848e14d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2340,7 +2340,7 @@ dependencies = [ "serde-bench 0.0.7 (registry+https://github.com/rust-lang/crates.io-index)", "serde_bytes 0.10.5 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmparser 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)", + "wasmparser 0.29.2 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2382,6 +2382,11 @@ name = "wasmparser" version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "wasmparser" +version = "0.29.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "which" version = "2.0.1" @@ -2755,6 +2760,7 @@ dependencies = [ "checksum wasmparser 0.22.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f46e666ecb4a406483a59a49f9d0c17f327e70da53a128eccddae2eadb95865c" "checksum wasmparser 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b5e01c420bc7d36e778bd242e1167b079562ba8b34087122cc9057187026d060" "checksum wasmparser 0.28.0 (registry+https://github.com/rust-lang/crates.io-index)" = "40f426b1929bd26517fb10702e2a8e520d1845c49567aa4d244f426f10b206c1" +"checksum wasmparser 0.29.2 (registry+https://github.com/rust-lang/crates.io-index)" = "981a8797cf89762e0233ec45fae731cb79a4dfaee12d9f0fe6cee01e4ac58d00" "checksum which 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b57acb10231b9493c8472b20cb57317d0679a49e0bdbee44b3b803a6473af164" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" "checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0" diff --git a/lib/runtime-core/Cargo.toml b/lib/runtime-core/Cargo.toml index 43864339702..215df568a4d 100644 --- a/lib/runtime-core/Cargo.toml +++ b/lib/runtime-core/Cargo.toml @@ -10,7 +10,7 @@ edition = "2018" [dependencies] nix = "0.12.0" page_size = "0.4.1" -wasmparser = "0.23.0" +wasmparser = "0.29.2" parking_lot = "0.7.1" lazy_static = "1.2.0" indexmap = "1.0.2" diff --git a/lib/runtime-core/src/lib.rs b/lib/runtime-core/src/lib.rs index 36bfcc22105..7042983d213 100644 --- a/lib/runtime-core/src/lib.rs +++ b/lib/runtime-core/src/lib.rs @@ -93,13 +93,18 @@ pub fn compile_with_config( /// WebAssembly specification. Returns `true` if validation /// succeeded, `false` if validation failed. pub fn validate(wasm: &[u8]) -> bool { + validate_and_report_errors(wasm).is_ok() +} + +/// The same as `validate` but with an Error message on failure +pub fn validate_and_report_errors(wasm: &[u8]) -> ::std::result::Result<(), String> { use wasmparser::WasmDecoder; let mut parser = wasmparser::ValidatingParser::new(wasm, None); loop { let state = parser.read(); match *state { - wasmparser::ParserState::EndWasm => break true, - wasmparser::ParserState::Error(_) => break false, + wasmparser::ParserState::EndWasm => break Ok(()), + wasmparser::ParserState::Error(e) => break Err(format!("{}", e)), _ => {} } } diff --git a/lib/runtime-core/src/module.rs b/lib/runtime-core/src/module.rs index b0c33406e4b..65817399d25 100644 --- a/lib/runtime-core/src/module.rs +++ b/lib/runtime-core/src/module.rs @@ -73,7 +73,7 @@ impl ModuleInfo { let len = reader.bytes_remaining(); let bytes = reader.read_bytes(len)?; let data = bytes.to_vec(); - let name = String::from_utf8_lossy(name).to_string(); + let name = name.to_string(); self.custom_sections.insert(name, data); } } diff --git a/src/bin/wasmer.rs b/src/bin/wasmer.rs index f29f3e63484..cd160aff6ce 100644 --- a/src/bin/wasmer.rs +++ b/src/bin/wasmer.rs @@ -14,7 +14,7 @@ use wasmer::webassembly::InstanceABI; use wasmer::*; use wasmer_emscripten; use wasmer_runtime::cache::{Cache as BaseCache, FileSystemCache, WasmHash, WASMER_VERSION_HASH}; -use wasmer_runtime_core::backend::CompilerConfig; +use wasmer_runtime_core::{self, backend::CompilerConfig}; #[derive(Debug, StructOpt)] #[structopt(name = "wasmer", about = "Wasm execution runtime.")] @@ -270,15 +270,8 @@ fn validate_wasm(validate: Validate) -> Result<(), String> { )); } - wabt::Module::read_binary(wasm_binary, &Default::default()) - .map_err(|err| { - format!( - "Failed to read \"{}\" as a WASM binary: {}", - wasm_path_as_str, err - ) - })? - .validate() - .map_err(|err| format!("Failed to validate \"{}\": {}", wasm_path_as_str, err))?; + wasmer_runtime_core::validate_and_report_errors(&wasm_binary) + .map_err(|err| format!("Validation failed: {}", err))?; Ok(()) }