Skip to content

Commit 7294f68

Browse files
authored
Merge branch 'master' into rename_enoent
2 parents dbba897 + 4406f59 commit 7294f68

24 files changed

+370
-104
lines changed

.gitattributes

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
CHANGELOG.md merge=union
22
*.wast linguist-vendored
33
*.wat linguist-vendored
4+
* -text

.github/workflows/benchmark.yaml

-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ jobs:
1717
- build: linux
1818
os: ubuntu-latest
1919
env:
20-
CARGO_SCCACHE_VERSION: 0.2.13
2120
SCCACHE_AZURE_BLOB_CONTAINER: wasmerstoragesccacheblob
2221
SCCACHE_AZURE_CONNECTION_STRING: ${{ secrets.SCCACHE_AZURE_CONNECTION_STRING }}
2322
steps:

.github/workflows/test-sys.yaml

+1-2
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,6 @@ jobs:
9393
use_sccache: false
9494
container: ${{ matrix.container }}
9595
env:
96-
CARGO_SCCACHE_VERSION: 0.2.14-alpha.0-parity
9796
SCCACHE_AZURE_BLOB_CONTAINER: wasmerstoragesccacheblob
9897
SCCACHE_AZURE_CONNECTION_STRING: ${{ secrets.SCCACHE_AZURE_CONNECTION_STRING }}
9998
TARGET: ${{ matrix.target }}
@@ -162,7 +161,7 @@ jobs:
162161
if: matrix.use_sccache
163162
run: |
164163
if [ ! -f '${{ runner.tool_cache }}/cargo-sccache/bin/sccache' ]; then
165-
cargo install sccache --git https://github.com/wasmerio/sccache.git --no-default-features --features=dist-client,azure --root '${{ runner.tool_cache }}/cargo-sccache'
164+
cargo install sccache --no-default-features --features=dist-client,azure --root '${{ runner.tool_cache }}/cargo-sccache'
166165
fi
167166
shell: bash
168167
- name: Setup Rust target

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ Looking for changes that affect our C API? See the [C API Changelog](lib/c-api/C
1313
- [#2535](https://github.com/wasmerio/wasmer/pull/2435) Added iOS support for Wasmer. This relies on the `dylib-engine`.
1414
- [#2427](https://github.com/wasmerio/wasmer/pull/2427) Wasmer can now compile to Javascript via `wasm-bindgen`. Use the `js-default` (and no default features) feature to try it!.
1515
- [#2436](https://github.com/wasmerio/wasmer/pull/2436) Added the x86-32 bit variant support to LLVM compiler.
16+
- [#2499](https://github.com/wasmerio/wasmer/pull/2499) Added a subcommand to linux wasmer-cli to register wasmer with binfmt_misc
17+
1618

1719
### Changed
1820
- [#2460](https://github.com/wasmerio/wasmer/pull/2460) **breaking change** `wasmer` API usage with `no-default-features` requires now the `sys` feature to preserve old behavior.

Cargo.lock

+20-20
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

PACKAGING.md

+6
Original file line numberDiff line numberDiff line change
@@ -46,3 +46,9 @@
4646
* `libwasmer-static`, containing `libwasmer.a`.
4747

4848
The Wasmer distro packaging story is still in its infancy, so feedback is very welcome.
49+
50+
## Miscellaneous: binfmt_misc
51+
52+
Wasmer can be registered as a binfmt interpreter for wasm binaries.
53+
An example systemd [.service](./scripts/wasmer-binfmt.service.example) is included here.
54+
Please consider statically linking the wasmer binary so that this capability is also available in mount namespaces.

lib/cli/src/cli.rs

+30-13
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
//! The logic for the Wasmer CLI tool.
22
3+
#[cfg(target_os = "linux")]
4+
use crate::commands::Binfmt;
35
#[cfg(feature = "compiler")]
46
use crate::commands::Compile;
57
#[cfg(all(feature = "staticlib", feature = "compiler"))]
@@ -66,6 +68,11 @@ enum WasmerCLIOptions {
6668
#[cfg(feature = "wast")]
6769
#[structopt(name = "wast")]
6870
Wast(Wast),
71+
72+
/// Unregister and/or register wasmer as binfmt interpreter
73+
#[cfg(target_os = "linux")]
74+
#[structopt(name = "binfmt")]
75+
Binfmt(Binfmt),
6976
}
7077

7178
impl WasmerCLIOptions {
@@ -83,6 +90,8 @@ impl WasmerCLIOptions {
8390
Self::Inspect(inspect) => inspect.execute(),
8491
#[cfg(feature = "wast")]
8592
Self::Wast(wast) => wast.execute(),
93+
#[cfg(target_os = "linux")]
94+
Self::Binfmt(binfmt) => binfmt.execute(),
8695
}
8796
}
8897
}
@@ -97,21 +106,29 @@ pub fn wasmer_main() {
97106
// Eg. `wasmer <SUBCOMMAND>`
98107
// In case that fails, we fallback trying the Run subcommand directly.
99108
// Eg. `wasmer myfile.wasm --dir=.`
109+
//
110+
// In case we've been run as wasmer-binfmt-interpreter myfile.wasm args,
111+
// we assume that we're registered via binfmt_misc
100112
let args = std::env::args().collect::<Vec<_>>();
113+
let binpath = args.get(0).map(|s| s.as_ref()).unwrap_or("");
101114
let command = args.get(1);
102-
let options = match command.unwrap_or(&"".to_string()).as_ref() {
103-
"cache" | "compile" | "config" | "create-exe" | "help" | "inspect" | "run"
104-
| "self-update" | "validate" | "wast" => WasmerCLIOptions::from_args(),
105-
_ => {
106-
WasmerCLIOptions::from_iter_safe(args.iter()).unwrap_or_else(|e| {
107-
match e.kind {
108-
// This fixes a issue that:
109-
// 1. Shows the version twice when doing `wasmer -V`
110-
// 2. Shows the run help (instead of normal help) when doing `wasmer --help`
111-
ErrorKind::VersionDisplayed | ErrorKind::HelpDisplayed => e.exit(),
112-
_ => WasmerCLIOptions::Run(Run::from_args()),
113-
}
114-
})
115+
let options = if cfg!(target_os = "linux") && binpath.ends_with("wasmer-binfmt-interpreter") {
116+
WasmerCLIOptions::Run(Run::from_binfmt_args())
117+
} else {
118+
match command.unwrap_or(&"".to_string()).as_ref() {
119+
"cache" | "compile" | "config" | "create-exe" | "help" | "inspect" | "run"
120+
| "self-update" | "validate" | "wast" | "binfmt" => WasmerCLIOptions::from_args(),
121+
_ => {
122+
WasmerCLIOptions::from_iter_safe(args.iter()).unwrap_or_else(|e| {
123+
match e.kind {
124+
// This fixes a issue that:
125+
// 1. Shows the version twice when doing `wasmer -V`
126+
// 2. Shows the run help (instead of normal help) when doing `wasmer --help`
127+
ErrorKind::VersionDisplayed | ErrorKind::HelpDisplayed => e.exit(),
128+
_ => WasmerCLIOptions::Run(Run::from_args()),
129+
}
130+
})
131+
}
115132
}
116133
};
117134

lib/cli/src/commands.rs

+4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
//! The commands available in the Wasmer binary.
2+
#[cfg(target_os = "linux")]
3+
mod binfmt;
24
mod cache;
35
#[cfg(feature = "compiler")]
46
mod compile;
@@ -12,6 +14,8 @@ mod validate;
1214
#[cfg(feature = "wast")]
1315
mod wast;
1416

17+
#[cfg(target_os = "linux")]
18+
pub use binfmt::*;
1519
#[cfg(feature = "compiler")]
1620
pub use compile::*;
1721
#[cfg(all(feature = "staticlib", feature = "compiler"))]

lib/cli/src/commands/binfmt.rs

+153
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
use anyhow::{Context, Result};
2+
use std::env;
3+
use std::fs;
4+
use std::io::Write;
5+
use std::os::unix::ffi::OsStrExt;
6+
use std::os::unix::fs::MetadataExt;
7+
use std::path::{Path, PathBuf};
8+
use structopt::StructOpt;
9+
use Action::*;
10+
11+
#[derive(StructOpt, Clone, Copy)]
12+
enum Action {
13+
/// Register wasmer as binfmt interpreter
14+
Register,
15+
/// Unregister a binfmt interpreter for wasm32
16+
Unregister,
17+
/// Soft unregister, and register
18+
Reregister,
19+
}
20+
21+
/// Unregister and/or register wasmer as binfmt interpreter
22+
///
23+
/// Check the wasmer repository for a systemd service definition example
24+
/// to automate the process at start-up.
25+
#[derive(StructOpt)]
26+
pub struct Binfmt {
27+
// Might be better to traverse the mount list
28+
/// Mount point of binfmt_misc fs
29+
#[structopt(long, default_value = "/proc/sys/fs/binfmt_misc/")]
30+
binfmt_misc: PathBuf,
31+
32+
#[structopt(subcommand)]
33+
action: Action,
34+
}
35+
36+
// Quick safety check:
37+
// This folder isn't world writeable (or else its sticky bit is set), and neither are its parents.
38+
//
39+
// If somebody mounted /tmp wrong, this might result in a TOCTOU problem.
40+
fn seccheck(path: &Path) -> Result<()> {
41+
if let Some(parent) = path.parent() {
42+
seccheck(parent)?;
43+
}
44+
let m = std::fs::metadata(path)
45+
.with_context(|| format!("Can't check permissions of {}", path.to_string_lossy()))?;
46+
anyhow::ensure!(
47+
m.mode() & 0o2 == 0 || m.mode() & 0o1000 != 0,
48+
"{} is world writeable and not sticky",
49+
path.to_string_lossy()
50+
);
51+
Ok(())
52+
}
53+
54+
impl Binfmt {
55+
/// execute [Binfmt]
56+
pub fn execute(&self) -> Result<()> {
57+
if !self.binfmt_misc.exists() {
58+
panic!("{} does not exist", self.binfmt_misc.to_string_lossy());
59+
}
60+
let temp_dir;
61+
let specs = match self.action {
62+
Register | Reregister => {
63+
temp_dir = tempfile::tempdir().context("Make temporary directory")?;
64+
seccheck(temp_dir.path())?;
65+
let bin_path_orig: PathBuf = env::args_os()
66+
.nth(0)
67+
.map(Into::into)
68+
.filter(|p: &PathBuf| p.exists())
69+
.context("Cannot get path to wasmer executable")?;
70+
let bin_path = temp_dir.path().join("wasmer-binfmt-interpreter");
71+
fs::copy(&bin_path_orig, &bin_path).context("Copy wasmer binary to temp folder")?;
72+
let bin_path = fs::canonicalize(&bin_path).with_context(|| {
73+
format!(
74+
"Couldn't get absolute path for {}",
75+
bin_path.to_string_lossy()
76+
)
77+
})?;
78+
Some([
79+
[
80+
b":wasm32:M::\\x00asm\\x01\\x00\\x00::".as_ref(),
81+
bin_path.as_os_str().as_bytes(),
82+
b":PFC",
83+
]
84+
.concat(),
85+
[
86+
b":wasm32-wat:E::wat::".as_ref(),
87+
bin_path.as_os_str().as_bytes(),
88+
b":PFC",
89+
]
90+
.concat(),
91+
])
92+
}
93+
_ => None,
94+
};
95+
let wasm_registration = self.binfmt_misc.join("wasm32");
96+
let wat_registration = self.binfmt_misc.join("wasm32-wat");
97+
match self.action {
98+
Reregister | Unregister => {
99+
let unregister = [wasm_registration, wat_registration]
100+
.iter()
101+
.map(|registration| {
102+
if registration.exists() {
103+
let mut registration = fs::OpenOptions::new()
104+
.write(true)
105+
.open(registration)
106+
.context("Open existing binfmt entry to remove")?;
107+
registration
108+
.write_all(b"-1")
109+
.context("Couldn't write binfmt unregister request")?;
110+
Ok(true)
111+
} else {
112+
eprintln!(
113+
"Warning: {} does not exist, not unregistered.",
114+
registration.to_string_lossy()
115+
);
116+
Ok(false)
117+
}
118+
})
119+
.collect::<Vec<_>>()
120+
.into_iter()
121+
.collect::<Result<Vec<_>>>()?;
122+
match (self.action, unregister.into_iter().any(|b| b)) {
123+
(Unregister, false) => bail!("Nothing unregistered"),
124+
_ => (),
125+
}
126+
}
127+
_ => (),
128+
};
129+
if let Some(specs) = specs {
130+
if cfg!(target_env = "gnu") {
131+
// Approximate. ELF parsing for a proper check feels like overkill here.
132+
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.");
133+
}
134+
specs
135+
.iter()
136+
.map(|spec| {
137+
let register = self.binfmt_misc.join("register");
138+
let mut register = fs::OpenOptions::new()
139+
.write(true)
140+
.open(register)
141+
.context("Open binfmt misc for registration")?;
142+
register
143+
.write_all(&spec)
144+
.context("Couldn't register binfmt")?;
145+
Ok(())
146+
})
147+
.collect::<Vec<_>>()
148+
.into_iter()
149+
.collect::<Result<Vec<_>>>()?;
150+
}
151+
Ok(())
152+
}
153+
}

lib/cli/src/commands/compile.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ pub struct Compile {
2727
#[structopt(flatten)]
2828
store: StoreOptions,
2929

30-
#[structopt(short = "m", multiple = true)]
30+
#[structopt(short = "m", multiple = true, number_of_values = 1)]
3131
cpu_features: Vec<CpuFeature>,
3232
}
3333

lib/cli/src/commands/create_exe.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,12 @@ pub struct CreateExe {
2929
#[structopt(flatten)]
3030
compiler: CompilerOptions,
3131

32-
#[structopt(short = "m", multiple = true)]
32+
#[structopt(short = "m", multiple = true, number_of_values = 1)]
3333
cpu_features: Vec<CpuFeature>,
3434

3535
/// Additional libraries to link against.
3636
/// This is useful for fixing linker errors that may occur on some systems.
37-
#[structopt(short = "l", multiple = true)]
37+
#[structopt(short = "l", multiple = true, number_of_values = 1)]
3838
libraries: Vec<String>,
3939
}
4040

0 commit comments

Comments
 (0)