feat: Implement safe, checked module artifact deserialization

Enable rkyv validation of serialized module artifacts.

Required additions:
* derive the required CheckBytes trait for all types
* Add `_checked` variants of all the deserialization functions

Also enables the `strict` feature of rkyv by default.
This will ensure consistent archive binary layout across architectures
and Rust compiler versions.
This commit is contained in:
Christoph Herzog
2023-03-31 11:54:10 +02:00
committed by Christoph Herzog
parent 9cb4bf32c9
commit 47cc5bbf99
29 changed files with 327 additions and 28 deletions

View File

@@ -238,6 +238,18 @@ impl Module {
return Err(DeserializeError::Generic("You need to enable the `js-serializable-module` feature flag to deserialize a `Module`".to_string()));
}
pub fn deserialize_checked(
_engine: &impl AsEngineRef,
_bytes: impl IntoBytes,
) -> Result<Self, DeserializeError> {
#[cfg(feature = "js-serializable-module")]
return Self::from_binary(_engine, &_bytes.into_bytes())
.map_err(|e| DeserializeError::Compiler(e));
#[cfg(not(feature = "js-serializable-module"))]
return Err(DeserializeError::Generic("You need to enable the `js-serializable-module` feature flag to deserialize a `Module`".to_string()));
}
pub unsafe fn deserialize_from_file(
engine: &impl AsEngineRef,
path: impl AsRef<Path>,
@@ -246,6 +258,14 @@ impl Module {
Self::deserialize(engine, bytes)
}
pub fn deserialize_from_file_checked(
engine: &impl AsEngineRef,
path: impl AsRef<Path>,
) -> Result<Self, DeserializeError> {
let bytes = std::fs::read(path.as_ref())?;
Self::deserialize_checked(engine, bytes)
}
pub fn set_name(&mut self, name: &str) -> bool {
self.name = Some(name.to_string());
true

View File

@@ -219,6 +219,8 @@ impl Module {
/// Deserializes a serialized Module binary into a `Module`.
///
/// Note: You should usually prefer the safe [`Module::deserialize_checked`].
///
/// # Important
///
/// This function only accepts a custom binary format, which will be different
@@ -253,6 +255,56 @@ impl Module {
Ok(Self(module_imp::Module::deserialize(engine, bytes)?))
}
/// Deserializes a serialized Module binary into a `Module`.
///
/// # Important
///
/// This function only accepts a custom binary format, which will be different
/// than the `wasm` binary format and may change among Wasmer versions.
/// (it should be the result of the serialization of a Module via the
/// `Module::serialize` method.).
///
/// # Usage
///
/// ```ignore
/// # use wasmer::*;
/// # fn main() -> anyhow::Result<()> {
/// # let mut store = Store::default();
/// let module = Module::deserialize_checked(&store, serialized_data)?;
/// # Ok(())
/// # }
/// ```
pub fn deserialize_checked(
engine: &impl AsEngineRef,
bytes: impl IntoBytes,
) -> Result<Self, DeserializeError> {
Ok(Self(module_imp::Module::deserialize_checked(
engine, bytes,
)?))
}
/// Deserializes a a serialized Module located in a `Path` into a `Module`.
/// > Note: the module has to be serialized before with the `serialize` method.
///
/// # Usage
///
/// ```ignore
/// # use wasmer::*;
/// # let mut store = Store::default();
/// # fn main() -> anyhow::Result<()> {
/// let module = Module::deserialize_from_file(&store, path)?;
/// # Ok(())
/// # }
/// ```
pub fn deserialize_from_file_checked(
engine: &impl AsEngineRef,
path: impl AsRef<Path>,
) -> Result<Self, DeserializeError> {
Ok(Self(module_imp::Module::deserialize_from_file_checked(
engine, path,
)?))
}
/// Deserializes a a serialized Module located in a `Path` into a `Module`.
/// > Note: the module has to be serialized before with the `serialize` method.
///

View File

@@ -78,6 +78,19 @@ impl Module {
Ok(Self::from_artifact(artifact))
}
pub fn deserialize_checked(
engine: &impl AsEngineRef,
bytes: impl IntoBytes,
) -> Result<Self, DeserializeError> {
let bytes = bytes.into_bytes();
let artifact = engine
.as_engine_ref()
.engine()
.0
.deserialize_checked(&bytes)?;
Ok(Self::from_artifact(artifact))
}
pub unsafe fn deserialize_from_file(
engine: &impl AsEngineRef,
path: impl AsRef<Path>,
@@ -90,6 +103,18 @@ impl Module {
Ok(Self::from_artifact(artifact))
}
pub fn deserialize_from_file_checked(
engine: &impl AsEngineRef,
path: impl AsRef<Path>,
) -> Result<Self, DeserializeError> {
let artifact = engine
.as_engine_ref()
.engine()
.0
.deserialize_from_file_checked(path.as_ref())?;
Ok(Self::from_artifact(artifact))
}
fn from_artifact(artifact: Arc<Artifact>) -> Self {
Self { artifact }
}