From 895ee2b85f20784be51942a618dc0ca92f2cd79e Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Fri, 4 Jun 2021 12:18:02 -0700 Subject: [PATCH] make Module::deserialize's version check optional via Config (#2945) * make Module::deserialize's version check optional via Config A SerializedModule contains the CARGO_PKG_VERSION string, which is checked for equality when loading. This is a great guard-rail but some users may want to disable this check (e.g. so they can implement their own versioning scheme) * rename config to deserialize_check_wasmtime_version * add test * fix doc links * fix * thank you rustdoc --- crates/wasmtime/src/config.rs | 16 ++++++++++++++++ crates/wasmtime/src/module.rs | 5 ++++- crates/wasmtime/src/module/serialization.rs | 16 +++++++++------- tests/all/module_serialize.rs | 7 +++++++ 4 files changed, 36 insertions(+), 8 deletions(-) diff --git a/crates/wasmtime/src/config.rs b/crates/wasmtime/src/config.rs index 5cd16be24c..28cc85f3c2 100644 --- a/crates/wasmtime/src/config.rs +++ b/crates/wasmtime/src/config.rs @@ -291,6 +291,7 @@ pub struct Config { #[cfg(feature = "async")] pub(crate) async_stack_size: usize, pub(crate) async_support: bool, + pub(crate) deserialize_check_wasmtime_version: bool, } impl Config { @@ -326,6 +327,7 @@ impl Config { #[cfg(feature = "async")] async_stack_size: 2 << 20, async_support: false, + deserialize_check_wasmtime_version: true, }; ret.cranelift_debug_verifier(false); ret.cranelift_opt_level(OptLevel::Speed); @@ -1093,6 +1095,20 @@ impl Config { self } + /// Configure whether deserialized modules should validate version + /// information. This only effects [`crate::Module::deserialize()`], which is + /// used to load compiled code from trusted sources. When true, + /// [`crate::Module::deserialize()`] verifies that the wasmtime crate's + /// `CARGO_PKG_VERSION` matches with the version in the binary, which was + /// produced by [`crate::Module::serialize`] or + /// [`crate::Engine::precompile_module`]. + /// + /// This value defaults to true. + pub fn deserialize_check_wasmtime_version(&mut self, check: bool) -> &mut Self { + self.deserialize_check_wasmtime_version = check; + self + } + pub(crate) fn target_isa(&self) -> Box { self.isa_flags .clone() diff --git a/crates/wasmtime/src/module.rs b/crates/wasmtime/src/module.rs index 4964189d7b..2a9168f8f8 100644 --- a/crates/wasmtime/src/module.rs +++ b/crates/wasmtime/src/module.rs @@ -356,7 +356,10 @@ impl Module { /// blobs across versions of wasmtime you can be safely guaranteed that /// future versions of wasmtime will reject old cache entries). pub unsafe fn deserialize(engine: &Engine, bytes: impl AsRef<[u8]>) -> Result { - let module = SerializedModule::from_bytes(bytes.as_ref())?; + let module = SerializedModule::from_bytes( + bytes.as_ref(), + engine.config().deserialize_check_wasmtime_version, + )?; module.into_module(engine) } diff --git a/crates/wasmtime/src/module/serialization.rs b/crates/wasmtime/src/module/serialization.rs index e566d01ed5..e7861f419a 100644 --- a/crates/wasmtime/src/module/serialization.rs +++ b/crates/wasmtime/src/module/serialization.rs @@ -329,7 +329,7 @@ impl<'a> SerializedModule<'a> { Ok(bytes) } - pub fn from_bytes(bytes: &[u8]) -> Result { + pub fn from_bytes(bytes: &[u8], check_version: bool) -> Result { if !bytes.starts_with(HEADER) { bail!("bytes are not a compatible serialized wasmtime module"); } @@ -345,12 +345,14 @@ impl<'a> SerializedModule<'a> { bail!("serialized data is malformed"); } - let version = std::str::from_utf8(&bytes[1..1 + version_len])?; - if version != env!("CARGO_PKG_VERSION") { - bail!( - "Module was compiled with incompatible Wasmtime version '{}'", - version - ); + if check_version { + let version = std::str::from_utf8(&bytes[1..1 + version_len])?; + if version != env!("CARGO_PKG_VERSION") { + bail!( + "Module was compiled with incompatible Wasmtime version '{}'", + version + ); + } } Ok(bincode_options() diff --git a/tests/all/module_serialize.rs b/tests/all/module_serialize.rs index aa1a6093ba..e444487a9e 100644 --- a/tests/all/module_serialize.rs +++ b/tests/all/module_serialize.rs @@ -24,6 +24,13 @@ fn test_version_mismatch() -> Result<()> { .starts_with("Module was compiled with incompatible Wasmtime version")), } + // Test deserialize_check_wasmtime_version, which disables the logic which rejects the above. + let mut config = Config::new(); + config.deserialize_check_wasmtime_version(false); + let engine = Engine::new(&config).unwrap(); + unsafe { Module::deserialize(&engine, &buffer) } + .expect("module with corrupt version should deserialize when check is disabled"); + Ok(()) }