Move precompiled module detection into wasmtime (#5342)
* Treat `-` as an alias to `/dev/stdin` This applies to unix targets only, as Windows does not have an appropriate alternative. * Add tests for piped modules from stdin This applies to unix targets only, as Windows does not have an appropriate alternative. * Move precompiled module detection into wasmtime Previously, wasmtime-cli checked the module to be loaded is precompiled or not, by pre-opening the given file path to check if the "\x7FELF" header exists. This commit moves this branch into the `Module::from_trusted_file`, which is only invoked with `--allow-precompiled` flag on CLI. The initial motivation of the commit is, feeding a module to wasmtime from piped inputs, is blocked by the pre-opening of the module. The `Module::from_trusted_file`, assumes the --allow-precompiled flag so there is no piped inputs, happily mmap-ing the module to test if the header exists. If --allow-precompiled is not supplied, the existing `Module::from_file` will be used, without the additional header check as the precompiled modules are intentionally not allowed on piped inputs for security measures. One caveat of this approach is that the user may be confused if he or she tries to execute a precompiled module without --allow-precompiled, as wasmtime shows an 'input bytes aren't valid utf-8' error, not directly getting what's going wrong. So this commit includes a hack-ish workaround for this. Thanks to @jameysharp for suggesting this idea with a detailed guidance.
This commit is contained in:
@@ -3,8 +3,6 @@
|
||||
use anyhow::{anyhow, bail, Context as _, Result};
|
||||
use clap::Parser;
|
||||
use once_cell::sync::Lazy;
|
||||
use std::fs::File;
|
||||
use std::io::Read;
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
use std::{
|
||||
@@ -29,6 +27,8 @@ fn parse_module(s: &OsStr) -> anyhow::Result<PathBuf> {
|
||||
Some("help") | Some("config") | Some("run") | Some("wast") | Some("compile") => {
|
||||
bail!("module name cannot be the same as a subcommand")
|
||||
}
|
||||
#[cfg(unix)]
|
||||
Some("-") => Ok(PathBuf::from("/dev/stdin")),
|
||||
_ => Ok(s.into()),
|
||||
}
|
||||
}
|
||||
@@ -423,27 +423,12 @@ impl RunCommand {
|
||||
}
|
||||
|
||||
fn load_module(&self, engine: &Engine, path: &Path) -> Result<Module> {
|
||||
// Peek at the first few bytes of the file to figure out if this is
|
||||
// something we can pass off to `deserialize_file` which is fastest if
|
||||
// we don't actually read the whole file into memory. Note that this
|
||||
// behavior is disabled by default, though, because it's not safe to
|
||||
// pass arbitrary user input to this command with `--allow-precompiled`
|
||||
let mut file =
|
||||
File::open(path).with_context(|| format!("failed to open: {}", path.display()))?;
|
||||
let mut magic = [0; 4];
|
||||
if let Ok(()) = file.read_exact(&mut magic) {
|
||||
if &magic == b"\x7fELF" {
|
||||
if self.allow_precompiled {
|
||||
return unsafe { Module::deserialize_file(engine, path) };
|
||||
}
|
||||
bail!(
|
||||
"cannot load precompiled module `{}` unless --allow-precompiled is passed",
|
||||
path.display()
|
||||
)
|
||||
}
|
||||
if self.allow_precompiled {
|
||||
unsafe { Module::from_trusted_file(engine, path) }
|
||||
} else {
|
||||
Module::from_file(engine, path)
|
||||
.context("if you're trying to run a precompiled module, pass --allow-precompiled")
|
||||
}
|
||||
|
||||
Module::from_file(engine, path)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user