From ea2bf1b3cc2e9603b9d69c4df02fc14e00481845 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Thu, 27 May 2021 15:15:26 -0700 Subject: [PATCH 1/6] 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) --- crates/wasmtime/src/config.rs | 15 +++++++++++++++ crates/wasmtime/src/module.rs | 3 ++- crates/wasmtime/src/module/serialization.rs | 16 +++++++++------- 3 files changed, 26 insertions(+), 8 deletions(-) diff --git a/crates/wasmtime/src/config.rs b/crates/wasmtime/src/config.rs index 5cd16be24c36..6797f9f00857 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) validate_module_version: bool, } impl Config { @@ -326,6 +327,7 @@ impl Config { #[cfg(feature = "async")] async_stack_size: 2 << 20, async_support: false, + validate_module_version: true, }; ret.cranelift_debug_verifier(false); ret.cranelift_opt_level(OptLevel::Speed); @@ -1093,6 +1095,19 @@ impl Config { self } + /// Configure whether deserialized modules should validate version + /// information. This only effects [`Module::from_bytes`], which is used to + /// load compiled code from trusted sources. When true, + /// [`Module::from_bytes`] verifies that the wasmtime crate's + /// `CARGO_PKG_VERSION` matches with the version in the binary, which was + /// produced by [`Module::serialize`] or [`Engine::precompile_module`]. + /// + /// This value defaults to true. + pub fn validate_module_version(&mut self, check: bool) -> &mut Self { + self.validate_module_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 4964189d7bb7..6619eb074b56 100644 --- a/crates/wasmtime/src/module.rs +++ b/crates/wasmtime/src/module.rs @@ -356,7 +356,8 @@ 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().validate_module_version)?; module.into_module(engine) } diff --git a/crates/wasmtime/src/module/serialization.rs b/crates/wasmtime/src/module/serialization.rs index e566d01ed5ff..e7861f419a5a 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() From f17516decee06a8b9810a2fe8511c7d2cf936011 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Fri, 28 May 2021 16:53:29 -0700 Subject: [PATCH 2/6] rename config to deserialize_check_wasmtime_version --- crates/wasmtime/src/config.rs | 8 ++++---- crates/wasmtime/src/module.rs | 6 ++++-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/crates/wasmtime/src/config.rs b/crates/wasmtime/src/config.rs index 6797f9f00857..fcbaf7187331 100644 --- a/crates/wasmtime/src/config.rs +++ b/crates/wasmtime/src/config.rs @@ -291,7 +291,7 @@ pub struct Config { #[cfg(feature = "async")] pub(crate) async_stack_size: usize, pub(crate) async_support: bool, - pub(crate) validate_module_version: bool, + pub(crate) deserialize_check_wasmtime_version: bool, } impl Config { @@ -327,7 +327,7 @@ impl Config { #[cfg(feature = "async")] async_stack_size: 2 << 20, async_support: false, - validate_module_version: true, + deserialize_check_wasmtime_version: true, }; ret.cranelift_debug_verifier(false); ret.cranelift_opt_level(OptLevel::Speed); @@ -1103,8 +1103,8 @@ impl Config { /// produced by [`Module::serialize`] or [`Engine::precompile_module`]. /// /// This value defaults to true. - pub fn validate_module_version(&mut self, check: bool) -> &mut Self { - self.validate_module_version = check; + pub fn deserialize_check_wasmtime_version(&mut self, check: bool) -> &mut Self { + self.deserialize_check_wasmtime_version = check; self } diff --git a/crates/wasmtime/src/module.rs b/crates/wasmtime/src/module.rs index 6619eb074b56..2a9168f8f8c1 100644 --- a/crates/wasmtime/src/module.rs +++ b/crates/wasmtime/src/module.rs @@ -356,8 +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(), engine.config().validate_module_version)?; + let module = SerializedModule::from_bytes( + bytes.as_ref(), + engine.config().deserialize_check_wasmtime_version, + )?; module.into_module(engine) } From c270b397ade5cd9c47688e9c0d66b2e3e57b246c Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Tue, 1 Jun 2021 14:23:37 -0700 Subject: [PATCH 3/6] add test --- tests/all/module_serialize.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/all/module_serialize.rs b/tests/all/module_serialize.rs index aa1a6093ba2f..fdfc5667f0ae 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); + unsafe { Module::deserialize(&engine, &buffer) } + .expect("module with corrupt version should deserialize when check is disabled"); + Ok(()) } From d637adce939ec27d5fc322be7540281853929f4c Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Thu, 3 Jun 2021 16:34:07 -0700 Subject: [PATCH 4/6] fix doc links --- crates/wasmtime/src/config.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/crates/wasmtime/src/config.rs b/crates/wasmtime/src/config.rs index fcbaf7187331..e4153ff49f07 100644 --- a/crates/wasmtime/src/config.rs +++ b/crates/wasmtime/src/config.rs @@ -1096,11 +1096,12 @@ impl Config { } /// Configure whether deserialized modules should validate version - /// information. This only effects [`Module::from_bytes`], which is used to - /// load compiled code from trusted sources. When true, - /// [`Module::from_bytes`] verifies that the wasmtime crate's + /// information. This only effects [`crate::Module::from_bytes`], which is + /// used to load compiled code from trusted sources. When true, + /// [`crate::Module::from_bytes`] verifies that the wasmtime crate's /// `CARGO_PKG_VERSION` matches with the version in the binary, which was - /// produced by [`Module::serialize`] or [`Engine::precompile_module`]. + /// 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 { From b9b512a7d87bbde5eaf011bac6ecbebfc02f3e6f Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Thu, 3 Jun 2021 16:35:22 -0700 Subject: [PATCH 5/6] fix --- tests/all/module_serialize.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/all/module_serialize.rs b/tests/all/module_serialize.rs index fdfc5667f0ae..e444487a9e07 100644 --- a/tests/all/module_serialize.rs +++ b/tests/all/module_serialize.rs @@ -27,7 +27,7 @@ fn test_version_mismatch() -> Result<()> { // 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); + let engine = Engine::new(&config).unwrap(); unsafe { Module::deserialize(&engine, &buffer) } .expect("module with corrupt version should deserialize when check is disabled"); From 66164eee2331e28d018025c5926da9ce49058938 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Fri, 4 Jun 2021 10:27:19 -0700 Subject: [PATCH 6/6] thank you rustdoc --- crates/wasmtime/src/config.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/wasmtime/src/config.rs b/crates/wasmtime/src/config.rs index e4153ff49f07..28cc85f3c286 100644 --- a/crates/wasmtime/src/config.rs +++ b/crates/wasmtime/src/config.rs @@ -1096,9 +1096,9 @@ impl Config { } /// Configure whether deserialized modules should validate version - /// information. This only effects [`crate::Module::from_bytes`], which is + /// information. This only effects [`crate::Module::deserialize()`], which is /// used to load compiled code from trusted sources. When true, - /// [`crate::Module::from_bytes`] verifies that the wasmtime crate's + /// [`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`].