mirror of
https://github.com/mii443/wasmer.git
synced 2025-12-03 03:08:22 +00:00
Subcommand for registering wasmer as a binfmt_misc interpreter
This commit is contained in:
committed by
Julius Michaelis
parent
08c885fa58
commit
0c8f4d13b2
@@ -6,6 +6,8 @@ use crate::commands::Compile;
|
||||
use crate::commands::CreateExe;
|
||||
#[cfg(feature = "wast")]
|
||||
use crate::commands::Wast;
|
||||
#[cfg(target_os = "linux")]
|
||||
use crate::commands::Binfmt;
|
||||
use crate::commands::{Cache, Config, Inspect, Run, SelfUpdate, Validate};
|
||||
use crate::error::PrettyError;
|
||||
use anyhow::Result;
|
||||
@@ -66,6 +68,11 @@ enum WasmerCLIOptions {
|
||||
#[cfg(feature = "wast")]
|
||||
#[structopt(name = "wast")]
|
||||
Wast(Wast),
|
||||
|
||||
/// Unregister and/or register wasmer as binfmt interpreter
|
||||
#[cfg(target_os = "linux")]
|
||||
#[structopt(name = "binfmt")]
|
||||
Binfmt(Binfmt),
|
||||
}
|
||||
|
||||
impl WasmerCLIOptions {
|
||||
@@ -83,6 +90,8 @@ impl WasmerCLIOptions {
|
||||
Self::Inspect(inspect) => inspect.execute(),
|
||||
#[cfg(feature = "wast")]
|
||||
Self::Wast(wast) => wast.execute(),
|
||||
#[cfg(target_os = "linux")]
|
||||
Self::Binfmt(binfmt) => binfmt.execute(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -109,7 +118,7 @@ pub fn wasmer_main() {
|
||||
} else {
|
||||
match command.unwrap_or(&"".to_string()).as_ref() {
|
||||
"cache" | "compile" | "config" | "create-exe" | "help" | "inspect" | "run"
|
||||
| "self-update" | "validate" | "wast" => WasmerCLIOptions::from_args(),
|
||||
| "self-update" | "validate" | "wast" | "binfmt" => WasmerCLIOptions::from_args(),
|
||||
_ => {
|
||||
WasmerCLIOptions::from_iter_safe(args.iter()).unwrap_or_else(|e| {
|
||||
match e.kind {
|
||||
|
||||
@@ -11,6 +11,8 @@ mod self_update;
|
||||
mod validate;
|
||||
#[cfg(feature = "wast")]
|
||||
mod wast;
|
||||
#[cfg(unix)]
|
||||
mod binfmt;
|
||||
|
||||
#[cfg(feature = "compiler")]
|
||||
pub use compile::*;
|
||||
@@ -18,4 +20,6 @@ pub use compile::*;
|
||||
pub use create_exe::*;
|
||||
#[cfg(feature = "wast")]
|
||||
pub use wast::*;
|
||||
#[cfg(unix)]
|
||||
pub use binfmt::*;
|
||||
pub use {cache::*, config::*, inspect::*, run::*, self_update::*, validate::*};
|
||||
|
||||
96
lib/cli/src/commands/binfmt.rs
Normal file
96
lib/cli/src/commands/binfmt.rs
Normal file
@@ -0,0 +1,96 @@
|
||||
use structopt::StructOpt;
|
||||
use anyhow::{Context, Result};
|
||||
use std::env;
|
||||
use std::path::{PathBuf, Path};
|
||||
use std::fs;
|
||||
use std::io::Write;
|
||||
use std::os::unix::ffi::OsStrExt;
|
||||
use std::os::unix::fs::MetadataExt;
|
||||
use Action::*;
|
||||
|
||||
#[derive(StructOpt)]
|
||||
enum Action {
|
||||
/// Register wasmer as binfmt interpreter
|
||||
Register,
|
||||
/// Unregister a binfmt interpreter for wasm32
|
||||
Unregister,
|
||||
/// Soft unregister, and register
|
||||
Reregister,
|
||||
}
|
||||
|
||||
/// Unregister and/or register wasmer as binfmt interpreter
|
||||
#[derive(StructOpt)]
|
||||
pub struct Binfmt {
|
||||
// Might be better to traverse the mount list
|
||||
/// Mount point of binfmt_misc fs
|
||||
#[structopt(default_value = "/proc/sys/fs/binfmt_misc/")]
|
||||
binfmt_misc: PathBuf,
|
||||
|
||||
#[structopt(subcommand)]
|
||||
action: Action,
|
||||
}
|
||||
|
||||
// Quick safety check:
|
||||
// This folder isn't world writeable (or else its sticky bit is set), and neither are its parents.
|
||||
//
|
||||
// If somebody mounted /tmp wrong, this might result in a TOCTOU problem.
|
||||
fn seccheck(path: &Path) -> Result<()> {
|
||||
let m = std::fs::metadata(path)
|
||||
.with_context(|| format!("Can't check permissions of {}", path.to_string_lossy()))?;
|
||||
anyhow::ensure!(m.mode() & 0o2 == 0 || m.mode() & 0o1000 != 0, "{} is world writeable and not sticky", path.to_string_lossy());
|
||||
if let Some(parent) = path.parent() {
|
||||
seccheck(parent)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
impl Binfmt {
|
||||
/// execute [Binfmt]
|
||||
pub fn execute(&self) -> Result<()> {
|
||||
if !self.binfmt_misc.exists() {
|
||||
panic!("{} does not exist", self.binfmt_misc.to_string_lossy());
|
||||
}
|
||||
let temp_dir;
|
||||
let spec = match self.action {
|
||||
Register | Reregister => {
|
||||
temp_dir = tempfile::tempdir().context("Make temporary directory")?;
|
||||
seccheck(temp_dir.path())?;
|
||||
let bin_path_orig: PathBuf = env::args_os().nth(0).map(Into::into).filter(|p: &PathBuf| p.exists())
|
||||
.context("Cannot get path to wasmer executable")?;
|
||||
let bin_path = temp_dir.path().join("wasmer-binfmt-interpreter");
|
||||
fs::copy(&bin_path_orig, &bin_path)
|
||||
.context("Copy wasmer binary to temp folder")?;
|
||||
let bin_path = fs::canonicalize(&bin_path)
|
||||
.with_context(|| format!("Couldn't get absolute path for {}", bin_path.to_string_lossy()))?;
|
||||
Some([b":wasm32:M::\\x00asm\\x01\\x00\\x00::".as_ref(), bin_path.as_os_str().as_bytes(), b":PFC"].concat())
|
||||
},
|
||||
_ => None
|
||||
};
|
||||
let registration = self.binfmt_misc.join("wasm32");
|
||||
let registration_exists = registration.exists();
|
||||
match self.action {
|
||||
Unregister if !registration_exists => {
|
||||
bail!("Cannot unregister binfmt, not registered");
|
||||
},
|
||||
Reregister | Unregister if registration.exists() => {
|
||||
let mut registration = fs::OpenOptions::new()
|
||||
.write(true)
|
||||
.open(registration).context("Open existing binfmt entry to remove")?;
|
||||
registration.write_all(b"-1").context("Couldn't write binfmt unregister request")?;
|
||||
},
|
||||
_ => (),
|
||||
};
|
||||
if cfg!(target_env = "gnu") {
|
||||
// Approximate. ELF parsing for a proper check feels like overkill here.
|
||||
eprintln!("Warning: wasmer has been compiled for glibc, and is thus likely dynamically linked. Invoking wasm binaries in chroots or mount namespaces (lxc, docker, ...) may not work.");
|
||||
}
|
||||
if let Some(spec) = spec {
|
||||
let register = self.binfmt_misc.join("register");
|
||||
let mut register = fs::OpenOptions::new()
|
||||
.write(true)
|
||||
.open(register).context("Open binfmt misc for registration")?;
|
||||
register.write_all(&spec).context("Couldn't register binfmt")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user