diff --git a/lib/cli/src/commands/run/mod.rs b/lib/cli/src/commands/run/mod.rs index 09144a88f3c..85c64b76402 100644 --- a/lib/cli/src/commands/run/mod.rs +++ b/lib/cli/src/commands/run/mod.rs @@ -390,7 +390,8 @@ impl Run { uses: Vec, runtime: Arc, ) -> Result<(), Error> { - let mut runner = self.build_wasi_runner(&runtime)?; + // Assume webcs are always WASIX + let mut runner = self.build_wasi_runner(&runtime, true)?; runner.run_command(command_name, pkg, runtime) } @@ -473,7 +474,7 @@ impl Run { pkg: &BinaryPackage, runtime: Arc, ) -> Result<(), Error> { - let mut inner = self.build_wasi_runner(&runtime)?; + let mut inner = self.build_wasi_runner(&runtime, true)?; let mut runner = wasmer_wasix::runners::dproxy::DProxyRunner::new(inner, pkg); runner.run_command(command_name, pkg, runtime) } @@ -516,13 +517,14 @@ impl Run { fn build_wasi_runner( &self, runtime: &Arc, + is_wasix: bool, ) -> Result { let packages = self.load_injected_packages(runtime)?; let mut runner = WasiRunner::new(); let (is_home_mapped, is_tmp_mapped, mapped_diretories) = - self.wasi.build_mapped_directories()?; + self.wasi.build_mapped_directories(is_wasix)?; runner .with_args(&self.args) @@ -581,7 +583,7 @@ impl Run { ) -> Result<(), Error> { let program_name = wasm_path.display().to_string(); - let runner = self.build_wasi_runner(&runtime)?; + let runner = self.build_wasi_runner(&runtime, wasmer_wasix::is_wasix_module(&module))?; runner.run_wasm(runtime, &program_name, module, module_hash) } diff --git a/lib/cli/src/commands/run/wasi.rs b/lib/cli/src/commands/run/wasi.rs index 22d0cc9713c..d308eba39ef 100644 --- a/lib/cli/src/commands/run/wasi.rs +++ b/lib/cli/src/commands/run/wasi.rs @@ -474,6 +474,7 @@ impl Wasi { pub fn build_mapped_directories( &self, + is_wasix: bool, ) -> Result<(bool, bool, Vec), anyhow::Error> { let mut mapped_dirs = Vec::new(); @@ -491,8 +492,14 @@ impl Wasi { MappedDirectory { host: current_dir, - guest: MAPPED_CURRENT_DIR_DEFAULT_PATH.to_string(), + guest: if is_wasix { + MAPPED_CURRENT_DIR_DEFAULT_PATH.to_string() + } else { + "/".to_string() + }, } + } else if dir == Path::new("/") && is_wasix { + bail!("Cannot pre-open the root directory with --dir=/ as mounting on the guest's virtual root is not allowed"); } else { let resolved = dir.canonicalize().with_context(|| { format!( @@ -528,11 +535,16 @@ impl Wasi { } for MappedDirectory { host, guest } in &self.mapped_dirs { + if guest == "/" && is_wasix { + // Note: it appears we canonicalize the path before this point and showing the value of + // `host` in the error message may throw users off, so we use a placeholder. + bail!("Mounting on the guest's virtual root with --mapdir /: is not allowed"); + } let resolved_host = host.canonicalize().with_context(|| { format!( "could not canonicalize path for argument '--mapdir {}:{}'", - host.display(), guest, + host.display(), ) })?; @@ -544,7 +556,11 @@ impl Wasi { MappedDirectory { host: resolved_host, - guest: MAPPED_CURRENT_DIR_DEFAULT_PATH.to_string(), + guest: if is_wasix { + MAPPED_CURRENT_DIR_DEFAULT_PATH.to_string() + } else { + "/".to_string() + }, } } else { MappedDirectory { diff --git a/lib/package/src/package/package.rs b/lib/package/src/package/package.rs index 4ca0f6955b1..2b96915e6ac 100644 --- a/lib/package/src/package/package.rs +++ b/lib/package/src/package/package.rs @@ -106,6 +106,9 @@ pub enum WasmerPackageError { /// A manifest validation error. #[error("The manifest is invalid")] Validation(#[from] wasmer_config::package::ValidationError), + /// Volumes can't be mounted on the guest's root + #[error("Mounting on the guest's root (e.g. \"/\" = \"\" in [fs] section of wasmer.toml) is not allowed")] + MountOnRoot, /// A path in the fs mapping does not exist #[error("Path: \"{}\" does not exist", path.display())] PathNotExists { @@ -225,6 +228,10 @@ impl Package { .expect("Canonicalizing should always result in a file with a parent directory") .to_path_buf(); + if wasmer_toml.fs.keys().any(|k| k == "/") { + return Err(WasmerPackageError::MountOnRoot); + } + for path in wasmer_toml.fs.values() { if !base_dir.join(path).exists() { return Err(WasmerPackageError::PathNotExists { path: path.clone() }); diff --git a/lib/wasix/src/runtime/package_loader/load_package_tree.rs b/lib/wasix/src/runtime/package_loader/load_package_tree.rs index 9850cff2b7d..53dbb85ae58 100644 --- a/lib/wasix/src/runtime/package_loader/load_package_tree.rs +++ b/lib/wasix/src/runtime/package_loader/load_package_tree.rs @@ -5,7 +5,7 @@ use std::{ sync::Arc, }; -use anyhow::{Context, Error}; +use anyhow::{bail, Context, Error}; use futures::{future::BoxFuture, StreamExt, TryStreamExt}; use once_cell::sync::OnceCell; use petgraph::visit::EdgeRef; @@ -399,9 +399,6 @@ fn filesystem_v3( ) -> Result, Error> { let mut volumes: HashMap<&PackageId, BTreeMap> = HashMap::new(); - let mut mountings: Vec<_> = pkg.filesystem.iter().collect(); - mountings.sort_by_key(|m| std::cmp::Reverse(m.mount_path.as_path())); - let union_fs = UnionFileSystem::new(); for ResolvedFileSystemMapping { @@ -415,6 +412,12 @@ fn filesystem_v3( continue; } + if mount_path.as_path() == Path::new("/") { + bail!( + "The \"{package}\" package wants to mount a volume at \"/\", but that's not allowed", + ); + } + // Note: We want to reuse existing Volume instances if we can. That way // we can keep the memory usage down. A webc::compat::Volume is // reference-counted, anyway. @@ -474,9 +477,6 @@ fn filesystem_v2( let mut filesystems = Vec::new(); let mut volumes: HashMap<&PackageId, BTreeMap> = HashMap::new(); - let mut mountings: Vec<_> = pkg.filesystem.iter().collect(); - mountings.sort_by_key(|m| std::cmp::Reverse(m.mount_path.as_path())); - for ResolvedFileSystemMapping { mount_path, volume_name, @@ -488,6 +488,12 @@ fn filesystem_v2( continue; } + if mount_path.as_path() == Path::new("/") { + bail!( + "The \"{package}\" package wants to mount a volume at \"/\", but that's not allowed", + ); + } + // Note: We want to reuse existing Volume instances if we can. That way // we can keep the memory usage down. A webc::compat::Volume is // reference-counted, anyway.