Skip to content
This repository was archived by the owner on Nov 10, 2022. It is now read-only.

Commit 92bb0a6

Browse files
committed
Add --module-on-fd CLI arg
This patch brings back the ability to load the module to be run from an open file descriptor, which must be 3 or higher (so as not to collide with stdin/stdout/stderr). It also tweaks CLI parsing slightly - the '--' separating wasmldr args from module args is now required. Signed-off-by: Will Woods <[email protected]>
1 parent 8673bbe commit 92bb0a6

File tree

3 files changed

+67
-25
lines changed

3 files changed

+67
-25
lines changed

README.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,9 @@ $ RUST_LOG=enarx_wasmldr=info RUST_BACKTRACE=1 cargo run return_1.wasm
2424
]
2525
```
2626

27-
On Unix platforms, the command can also read the workload from the
28-
file descriptor (3):
27+
On Unix platforms, the command can also read the workload from an open file descriptor:
2928
```console
30-
$ RUST_LOG=enarx_wasmldr=info RUST_BACKTRACE=1 cargo run 3< return_1.wasm
29+
$ RUST_LOG=enarx_wasmldr=info RUST_BACKTRACE=1 cargo run -- --module-on-fd=3 3< return_1.wasm
3130
```
3231

3332

src/cli.rs

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,22 @@
22

33
#![allow(missing_docs, unused_variables)] // This is a work-in-progress, so...
44

5+
use anyhow::{bail, Result};
56
use structopt::{clap::AppSettings, StructOpt};
67

7-
use anyhow::{bail, Result};
88
use std::path::PathBuf;
9+
use std::str::FromStr;
10+
11+
#[cfg(unix)]
12+
use std::os::unix::io::RawFd;
913

10-
// The main StructOpt for running `wasmldr` directly
14+
// The main StructOpt for CLI options
1115
#[derive(StructOpt, Debug)]
12-
#[structopt(setting=AppSettings::TrailingVarArg)]
16+
#[structopt(
17+
setting = AppSettings::DeriveDisplayOrder,
18+
setting = AppSettings::UnifiedHelpMessage,
19+
)]
20+
/// Enarx Keep Configurator and WebAssembly Loader
1321
pub struct RunOptions {
1422
/// Pass an environment variable to the program
1523
#[structopt(
@@ -25,15 +33,24 @@ pub struct RunOptions {
2533
#[structopt(long, value_name = "FUNCTION")]
2634
invoke: Option<String>,
2735

36+
/// Load WebAssembly module from the given FD (must be >=3)
37+
#[cfg(unix)]
38+
#[structopt(long, value_name = "FD", parse(try_from_str = parse_module_fd))]
39+
pub module_on_fd: Option<RawFd>,
40+
2841
// TODO: --inherit-env
2942
// TODO: --stdin, --stdout, --stderr
3043
/// Path of the WebAssembly module to run
31-
#[structopt(index = 1, required = true, value_name = "MODULE", parse(from_os_str))]
32-
pub module: PathBuf,
44+
#[structopt(
45+
index = 1,
46+
required_unless = "module-on-fd",
47+
value_name = "MODULE",
48+
parse(from_os_str)
49+
)]
50+
pub module: Option<PathBuf>,
3351

34-
// NOTE: this has to come last for TrailingVarArg
3552
/// Arguments to pass to the WebAssembly module
36-
#[structopt(value_name = "ARGS")]
53+
#[structopt(value_name = "ARGS", last = true)]
3754
pub args: Vec<String>,
3855
}
3956

@@ -44,3 +61,11 @@ fn parse_env_var(s: &str) -> Result<(String, String)> {
4461
}
4562
Ok((parts[0].to_owned(), parts[1].to_owned()))
4663
}
64+
65+
fn parse_module_fd(s: &str) -> Result<RawFd> {
66+
let fd = RawFd::from_str(s)?;
67+
if fd <= 2 {
68+
bail!("FD must be >= 3");
69+
}
70+
Ok(fd)
71+
}

src/main.rs

Lines changed: 33 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,9 @@
1919
//! ]
2020
//! ```
2121
//!
22-
//! On Unix platforms, the command can also read the workload from the
23-
//! file descriptor (3):
22+
//! On Unix platforms, the command can also read the workload from an open file descriptor:
2423
//! ```console
25-
//! $ RUST_LOG=enarx_wasmldr=info RUST_BACKTRACE=1 cargo run 3< return_1.wasm
24+
//! $ RUST_LOG=enarx_wasmldr=info RUST_BACKTRACE=1 cargo run -- --module-on-fd=3 3< return_1.wasm
2625
//! ```
2726
//!
2827
#![deny(missing_docs)]
@@ -31,14 +30,35 @@
3130
mod cli;
3231
mod workload;
3332

33+
use anyhow::{Context, Result};
34+
use cli::RunOptions;
3435
use log::{debug, info};
3536
use structopt::StructOpt;
3637

3738
use std::fs::File;
3839
use std::io::Read;
40+
#[cfg(unix)]
41+
use std::os::unix::io::FromRawFd;
3942

40-
fn main() {
41-
// Initialize the logger, taking settings from the default env vars
43+
// SAFETY: If opts.module_on_fd is Some(fd) we'll use File::from_raw_fd(fd),
44+
// which is unsafe if something else is using that fd already. So this function
45+
// is safe as long as it is called before anything else opens a file/socket/etc.
46+
// (parse_module_fd() enforces fd >= 3, so we can ignore stdin/out/err.)
47+
unsafe fn get_module_reader(opts: &RunOptions) -> Result<File> {
48+
#[cfg(unix)]
49+
if let Some(fd) = opts.module_on_fd {
50+
info!("reading module from fd {:?}", fd);
51+
return Ok(File::from_raw_fd(fd));
52+
};
53+
let path = opts.module.as_ref().expect("missing required arg");
54+
info!("reading module from {:?}", path);
55+
File::open(path).with_context(|| format!("failed opening {:?}", path))
56+
}
57+
58+
fn main() -> Result<()> {
59+
// Initialize the logger, taking filtering and style settings from the
60+
// default env vars (RUST_LOG and RUST_LOG_STYLE).
61+
// The log target is the default target (stderr), so no files get opened.
4262
env_logger::Builder::from_default_env().init();
4363

4464
info!("version {} starting up", env!("CARGO_PKG_VERSION"));
@@ -47,22 +67,20 @@ fn main() {
4767
let opts = cli::RunOptions::from_args();
4868
info!("opts: {:#?}", opts);
4969

50-
info!("reading {:?}", opts.module);
51-
// TODO: don't just panic here...
52-
let mut reader = File::open(&opts.module).expect("Unable to open file");
53-
70+
// SAFETY: This is safe because we haven't opened anything else yet.
71+
let mut reader = unsafe { get_module_reader(&opts) }?;
5472
let mut bytes = Vec::new();
55-
reader
56-
.read_to_end(&mut bytes)
57-
.expect("Failed to load workload");
73+
reader.read_to_end(&mut bytes).context("loading module")?;
5874

59-
// FUTURE: measure opts.envs, opts.args, opts.wasm_features
60-
// FUTURE: fork() the workload off into a separate memory space
75+
// FUTURE: measure opts.envs, opts.args, opts.wasm_features, etc
76+
// FUTURE: fork() the workload off into a separate memory space?
6177

78+
// TODO: configure wasmtime, stdio, etc.
6279
info!("running workload");
63-
// TODO: pass opts.wasm_features
6480
let result = workload::run(bytes, opts.args, opts.envs).expect("Failed to run workload");
6581
info!("got result: {:#?}", result);
6682
// TODO: exit with the resulting code, if the result is a return code
6783
// FUTURE: produce attestation report here
84+
85+
Ok(())
6886
}

0 commit comments

Comments
 (0)