Skip to content

Commit

Permalink
make Module::deserialize's version check optional via Config (#2945)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
Pat Hickey authored Jun 4, 2021
1 parent 357b4c7 commit 895ee2b
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 8 deletions.
16 changes: 16 additions & 0 deletions crates/wasmtime/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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<dyn TargetIsa> {
self.isa_flags
.clone()
Expand Down
5 changes: 4 additions & 1 deletion crates/wasmtime/src/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Module> {
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)
}

Expand Down
16 changes: 9 additions & 7 deletions crates/wasmtime/src/module/serialization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,7 @@ impl<'a> SerializedModule<'a> {
Ok(bytes)
}

pub fn from_bytes(bytes: &[u8]) -> Result<Self> {
pub fn from_bytes(bytes: &[u8], check_version: bool) -> Result<Self> {
if !bytes.starts_with(HEADER) {
bail!("bytes are not a compatible serialized wasmtime module");
}
Expand All @@ -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()
Expand Down
7 changes: 7 additions & 0 deletions tests/all/module_serialize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(())
}

Expand Down

0 comments on commit 895ee2b

Please sign in to comment.