From 210a9f81c91812357b131bb4b93f7244d3b53dbd Mon Sep 17 00:00:00 2001 From: Alice W Date: Thu, 19 Jun 2025 15:11:34 -0400 Subject: [PATCH 1/7] call lind --- crates/exec-wasmtime/src/lib.rs | 1 + crates/exec-wasmtime/src/lind.rs | 23 ++++ crates/exec-wasmtime/src/runtime/mod.rs | 151 +++++++++++++----------- 3 files changed, 104 insertions(+), 71 deletions(-) create mode 100644 crates/exec-wasmtime/src/lind.rs diff --git a/crates/exec-wasmtime/src/lib.rs b/crates/exec-wasmtime/src/lib.rs index d477f83ce..cf56f6644 100644 --- a/crates/exec-wasmtime/src/lib.rs +++ b/crates/exec-wasmtime/src/lib.rs @@ -10,6 +10,7 @@ mod log; mod runtime; mod workload; +mod lind; #[cfg(unix)] pub use log::Level as LogLevel; diff --git a/crates/exec-wasmtime/src/lind.rs b/crates/exec-wasmtime/src/lind.rs new file mode 100644 index 000000000..878a0e915 --- /dev/null +++ b/crates/exec-wasmtime/src/lind.rs @@ -0,0 +1,23 @@ +use anyhow::{Result, Context}; +use lind_wasm::cli::RunCommand; +use clap::Parser; +use std::fs::File; +use std::io::Write; +use tempfile::NamedTempFile; + +pub fn execute_wasm(wasm_bytes: &[u8], args: &[String]) -> Result { + + let mut file = NamedTempFile::new() + .context("failed to create temporary wasm file")?; + file.write_all(wasm_bytes) + .context("failed to write wasm to temporary file")?; + let path = file.path().to_string_lossy().to_string(); + + let mut argv = vec!["wasmtime run --wasi threads=y --wasi preview2=n".to_string(), path]; + argv.extend(args.iter().cloned()); + + let cmd = RunCommand::parse_from(argv); + cmd.execute().context("lind-wasm execution failed")?; + + Ok(0) +} diff --git a/crates/exec-wasmtime/src/runtime/mod.rs b/crates/exec-wasmtime/src/runtime/mod.rs index bec0ea740..9db3e432e 100644 --- a/crates/exec-wasmtime/src/runtime/mod.rs +++ b/crates/exec-wasmtime/src/runtime/mod.rs @@ -10,7 +10,7 @@ use self::io::null::Null; use self::io::stdio_file; //use self::net::{connect_file, listen_file}; -use super::{Package, Workload}; +use super::{Package, Workload, execute_wasm}; use anyhow::Context; use enarx_config::{Config, File}; @@ -30,76 +30,85 @@ impl Runtime { // Execute an Enarx [Package] #[instrument] pub fn execute(package: Package) -> anyhow::Result> { - let (prvkey, crtreq) = - identity::generate().context("failed to generate a private key and CSR")?; - + // let (prvkey, crtreq) = + // identity::generate().context("failed to generate a private key and CSR")?; + + // let Workload { webasm, config } = package.try_into()?; + // let Config { + // steward, + // args, + // files, + // env, + // } = config.unwrap_or_default(); + + // let certs = if let Some(url) = steward { + // identity::steward(&url, crtreq).context("failed to attest to Steward")? + // } else { + // identity::selfsigned(&prvkey).context("failed to generate self-signed certificates")? + // } + // .into_iter() + // .map(rustls::Certificate) + // .collect::>(); + + // let mut config = wasmtime::Config::new(); + // // config.wasm_reference_types(true); // Enable reference types + // // config.wasm_function_references(true); // Enable function references + // // config.wasm_gc(true); // Enable garbage collection + // config.wasm_backtrace(true); + // config.native_unwind_info(true); // Enable threads + // config.debug_info(true); // Enable debug info + // config.memory_init_cow(false); + // config.async_support(false); + + // let engine = trace_span!("initialize Wasmtime engine") + // .in_scope(|| Engine::new(&config)) + // .context("failed to create execution engine")?; + + // let mut linker = trace_span!("setup linker").in_scope(|| Linker::new(&engine)); + // trace_span!("link WASI") + // .in_scope(|| add_to_linker_sync(&mut linker, |s| s)) + // .context("failed to setup linker and link WASI")?; + + // let mut builder = WasiCtxBuilder::new(); + // builder.inherit_stdio(); + // builder.inherit_stdin(); + // builder.inherit_stderr(); + // // builder.args(&["main.wasm", "/etc/resolv.conf", "/etc/resolv.conf"]); + // builder.preopened_dir("/home", ".", DirPerms::all(), FilePerms::all()).expect("failed to open current directory"); + // // builder.preopened_dir("/tmp", "/tmp", DirPerms::all(), FilePerms::all()).expect("failed to open current directory"); + + // //fs::File::open("/home/lind/enarx/test.txt").map_err(|err| format!("error opening input fuckup /home/lind/enarx/test.txt: {}", err)).unwrap(); + + // let mut wstore = trace_span!("initialize Wasmtime store") + // .in_scope(|| Store::new(&engine, builder.build_p1())); + + // let module = trace_span!("compile Wasm") + // .in_scope(|| Module::from_binary(&engine, &webasm)) + // .context("failed to compile Wasm module")?; + // trace_span!("link Wasm") + // .in_scope(|| linker.module(&mut wstore, "", &module)) + // .context("failed to link module")?; + + // let mut ctx = wstore.as_context_mut(); + // let ctx = ctx.data_mut(); + + // let func = trace_span!("get default function") + // .in_scope(|| linker.get_default(&mut wstore, "")) + // .context("failed to get default function")?; + + // let mut values = vec![Val::null_any_ref(); func.ty(&wstore).results().len()]; + // trace_span!("execute default function") + // .in_scope(|| func.call(wstore, Default::default(), &mut values)) + // .context("failed to execute default function")?; + // Ok(values) let Workload { webasm, config } = package.try_into()?; - let Config { - steward, - args, - files, - env, - } = config.unwrap_or_default(); - - let certs = if let Some(url) = steward { - identity::steward(&url, crtreq).context("failed to attest to Steward")? - } else { - identity::selfsigned(&prvkey).context("failed to generate self-signed certificates")? - } - .into_iter() - .map(rustls::Certificate) - .collect::>(); - - let mut config = wasmtime::Config::new(); - // config.wasm_reference_types(true); // Enable reference types - // config.wasm_function_references(true); // Enable function references - // config.wasm_gc(true); // Enable garbage collection - config.wasm_backtrace(true); - config.native_unwind_info(true); // Enable threads - config.debug_info(true); // Enable debug info - config.memory_init_cow(false); - config.async_support(false); - - let engine = trace_span!("initialize Wasmtime engine") - .in_scope(|| Engine::new(&config)) - .context("failed to create execution engine")?; - - let mut linker = trace_span!("setup linker").in_scope(|| Linker::new(&engine)); - trace_span!("link WASI") - .in_scope(|| add_to_linker_sync(&mut linker, |s| s)) - .context("failed to setup linker and link WASI")?; - - let mut builder = WasiCtxBuilder::new(); - builder.inherit_stdio(); - builder.inherit_stdin(); - builder.inherit_stderr(); - // builder.args(&["main.wasm", "/etc/resolv.conf", "/etc/resolv.conf"]); - builder.preopened_dir("/home", ".", DirPerms::all(), FilePerms::all()).expect("failed to open current directory"); - // builder.preopened_dir("/tmp", "/tmp", DirPerms::all(), FilePerms::all()).expect("failed to open current directory"); - - //fs::File::open("/home/lind/enarx/test.txt").map_err(|err| format!("error opening input fuckup /home/lind/enarx/test.txt: {}", err)).unwrap(); - - let mut wstore = trace_span!("initialize Wasmtime store") - .in_scope(|| Store::new(&engine, builder.build_p1())); - - let module = trace_span!("compile Wasm") - .in_scope(|| Module::from_binary(&engine, &webasm)) - .context("failed to compile Wasm module")?; - trace_span!("link Wasm") - .in_scope(|| linker.module(&mut wstore, "", &module)) - .context("failed to link module")?; - - let mut ctx = wstore.as_context_mut(); - let ctx = ctx.data_mut(); - - let func = trace_span!("get default function") - .in_scope(|| linker.get_default(&mut wstore, "")) - .context("failed to get default function")?; - - let mut values = vec![Val::null_any_ref(); func.ty(&wstore).results().len()]; - trace_span!("execute default function") - .in_scope(|| func.call(wstore, Default::default(), &mut values)) - .context("failed to execute default function")?; - Ok(values) + let args = config + .as_ref() + .map(|cfg| cfg.args.clone()) + .unwrap_or_default(); + + let exit_code = execute_wasm(&webasm, &args)?; + Ok(vec![Val::I32(exit_code)]) + } } From 7a870c52b1c7d40a3d638fa1b1d775e923a4d477 Mon Sep 17 00:00:00 2001 From: Yaxuan-w Date: Tue, 8 Jul 2025 21:39:41 -0400 Subject: [PATCH 2/7] multi-process works with lind-wasm --- Cargo.lock | 642 ++++++++++++++++++++--- Cargo.toml | 9 +- crates/exec-wasmtime/Cargo.toml | 5 + crates/exec-wasmtime/src/lib.rs | 1 - crates/exec-wasmtime/src/lind.rs | 23 - crates/exec-wasmtime/src/runtime/mod.rs | 656 ++++++++++++++++++++---- 6 files changed, 1159 insertions(+), 177 deletions(-) delete mode 100644 crates/exec-wasmtime/src/lind.rs diff --git a/Cargo.lock b/Cargo.lock index 59032438c..c00a41e46 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -71,6 +71,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ "cfg-if 1.0.0", + "getrandom 0.2.15", "once_cell", "version_check", "zerocopy", @@ -365,6 +366,21 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" +[[package]] +name = "bit-set" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + [[package]] name = "bit_field" version = "0.10.2" @@ -430,6 +446,16 @@ dependencies = [ "piper", ] +[[package]] +name = "btree_monstrousity" +version = "0.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ec92912346b936c974181a172d9abc81f50d41e40118fc101dac8aa8134bee3" +dependencies = [ + "cfg-if 1.0.0", + "rustversion", +] + [[package]] name = "bumpalo" version = "3.17.0" @@ -448,6 +474,12 @@ version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f61dac84819c6588b558454b194026eb1f09c293b9036ae9b159e74e73ab6cf9" +[[package]] +name = "cache-padded" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "981520c98f422fcc584dc1a95c334e6953900b9106bc47a9839b81790009eb21" + [[package]] name = "camino" version = "1.1.9" @@ -698,13 +730,28 @@ dependencies = [ "libc", ] +[[package]] +name = "cranelift-bforest" +version = "0.110.0" +dependencies = [ + "cranelift-entity 0.110.0", +] + [[package]] name = "cranelift-bforest" version = "0.110.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a41b85213deedf877555a7878ca9fb680ccba8183611c4bb8030ed281b2ad83" dependencies = [ - "cranelift-entity", + "cranelift-entity 0.110.3", +] + +[[package]] +name = "cranelift-bitset" +version = "0.110.0" +dependencies = [ + "serde", + "serde_derive", ] [[package]] @@ -717,6 +764,27 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "cranelift-codegen" +version = "0.110.0" +dependencies = [ + "bumpalo", + "cranelift-bforest 0.110.0", + "cranelift-bitset 0.110.0", + "cranelift-codegen-meta 0.110.0", + "cranelift-codegen-shared 0.110.0", + "cranelift-control 0.110.0", + "cranelift-entity 0.110.0", + "cranelift-isle 0.110.0", + "gimli 0.28.1", + "hashbrown 0.14.5", + "log", + "regalloc2", + "rustc-hash", + "smallvec", + "target-lexicon", +] + [[package]] name = "cranelift-codegen" version = "0.110.3" @@ -724,13 +792,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ce027a7b16f8b86f60ff6819615273635186d607a0c225ee6ac340d7d18f978" dependencies = [ "bumpalo", - "cranelift-bforest", - "cranelift-bitset", - "cranelift-codegen-meta", - "cranelift-codegen-shared", - "cranelift-control", - "cranelift-entity", - "cranelift-isle", + "cranelift-bforest 0.110.3", + "cranelift-bitset 0.110.3", + "cranelift-codegen-meta 0.110.3", + "cranelift-codegen-shared 0.110.3", + "cranelift-control 0.110.3", + "cranelift-entity 0.110.3", + "cranelift-isle 0.110.3", "gimli 0.28.1", "hashbrown 0.14.5", "log", @@ -740,21 +808,39 @@ dependencies = [ "target-lexicon", ] +[[package]] +name = "cranelift-codegen-meta" +version = "0.110.0" +dependencies = [ + "cranelift-codegen-shared 0.110.0", +] + [[package]] name = "cranelift-codegen-meta" version = "0.110.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0a2d2ab65e6cbf91f81781d8da65ec2005510f18300eff21a99526ed6785863" dependencies = [ - "cranelift-codegen-shared", + "cranelift-codegen-shared 0.110.3", ] +[[package]] +name = "cranelift-codegen-shared" +version = "0.110.0" + [[package]] name = "cranelift-codegen-shared" version = "0.110.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "efcff860573cf3db9ae98fbd949240d78b319df686cc306872e7fab60e9c84d7" +[[package]] +name = "cranelift-control" +version = "0.110.0" +dependencies = [ + "arbitrary", +] + [[package]] name = "cranelift-control" version = "0.110.3" @@ -764,60 +850,106 @@ dependencies = [ "arbitrary", ] +[[package]] +name = "cranelift-entity" +version = "0.110.0" +dependencies = [ + "cranelift-bitset 0.110.0", + "serde", + "serde_derive", +] + [[package]] name = "cranelift-entity" version = "0.110.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d21d3089714278920030321829090d9482c91e5ff2339f2f697f8425bffdcba3" dependencies = [ - "cranelift-bitset", + "cranelift-bitset 0.110.3", "serde", "serde_derive", ] +[[package]] +name = "cranelift-frontend" +version = "0.110.0" +dependencies = [ + "cranelift-codegen 0.110.0", + "log", + "smallvec", + "target-lexicon", +] + [[package]] name = "cranelift-frontend" version = "0.110.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7308482930f2a2fad4fe25a06054f6f9a4ee1ab97264308c661b037cb60001a3" dependencies = [ - "cranelift-codegen", + "cranelift-codegen 0.110.3", "log", "smallvec", "target-lexicon", ] +[[package]] +name = "cranelift-isle" +version = "0.110.0" + [[package]] name = "cranelift-isle" version = "0.110.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab4c59e259dab0e6958dabcc536b30845574f027ba6e5000498cdaf7e7ed2d30" +[[package]] +name = "cranelift-native" +version = "0.110.0" +dependencies = [ + "cranelift-codegen 0.110.0", + "libc", + "target-lexicon", +] + [[package]] name = "cranelift-native" version = "0.110.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d77ac3dfb61ef3159998105116acdfeaec75e4296c43ee2dcc4ea39838c0080e" dependencies = [ - "cranelift-codegen", + "cranelift-codegen 0.110.3", "libc", "target-lexicon", ] +[[package]] +name = "cranelift-wasm" +version = "0.110.0" +dependencies = [ + "cranelift-codegen 0.110.0", + "cranelift-entity 0.110.0", + "cranelift-frontend 0.110.0", + "itertools 0.12.1", + "log", + "smallvec", + "wasmparser 0.211.1", + "wasmtime-types 23.0.0", +] + [[package]] name = "cranelift-wasm" version = "0.110.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d883f1b8d3d1dab4797407117bc8a1824f4a1fe86654aee2ee3205613f77d3e" dependencies = [ - "cranelift-codegen", - "cranelift-entity", - "cranelift-frontend", + "cranelift-codegen 0.110.3", + "cranelift-entity 0.110.3", + "cranelift-frontend 0.110.3", "itertools 0.12.1", "log", "smallvec", "wasmparser 0.212.0", - "wasmtime-types", + "wasmtime-types 23.0.3", ] [[package]] @@ -928,6 +1060,7 @@ dependencies = [ "lock_api", "once_cell", "parking_lot_core", + "serde", ] [[package]] @@ -1166,6 +1299,7 @@ dependencies = [ "libc", "once_cell", "pkcs8", + "rawposix", "ring 0.16.20", "rustix 0.38.44", "rustls 0.20.9", @@ -1181,11 +1315,15 @@ dependencies = [ "ureq", "url", "wasi-common", - "wasmtime", + "wasmtime 23.0.0", + "wasmtime-lind-common", + "wasmtime-lind-multi-process", + "wasmtime-lind-utils", "wasmtime-wasi", + "wasmtime-wasi-threads", "wat", "webpki-roots 0.22.6", - "wiggle", + "wiggle 23.0.3", "x509-cert", "zeroize", ] @@ -1374,6 +1512,15 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "fdtables" +version = "0.1.0" +dependencies = [ + "dashmap", + "lazy_static", + "libc", +] + [[package]] name = "ff" version = "0.13.0" @@ -1656,6 +1803,12 @@ dependencies = [ "subtle", ] +[[package]] +name = "half" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b43ede17f21864e81be2fa654110bf1e793774238d86ef8555c37e6519c0403" + [[package]] name = "hashbrown" version = "0.13.2" @@ -2065,6 +2218,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.14" @@ -2326,6 +2488,17 @@ dependencies = [ "memoffset", ] +[[package]] +name = "nodit" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f74369f80df24efd2266602fdcd8fcd56a17c2e2c94ab48d2f7a15eaa137bf49" +dependencies = [ + "btree_monstrousity", + "itertools 0.13.0", + "smallvec", +] + [[package]] name = "noted" version = "1.0.0" @@ -2812,6 +2985,18 @@ dependencies = [ "cc", ] +[[package]] +name = "quick_cache" +version = "0.6.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b450dad8382b1b95061d5ca1eb792081fb082adf48c678791fe917509596d5f" +dependencies = [ + "ahash", + "equivalent", + "hashbrown 0.15.2", + "parking_lot", +] + [[package]] name = "quote" version = "1.0.38" @@ -2892,6 +3077,24 @@ dependencies = [ "rand_core 0.5.1", ] +[[package]] +name = "rawposix" +version = "0.1.0" +dependencies = [ + "bit-set", + "dashmap", + "fdtables", + "lazy_static", + "libc", + "nodit", + "parking_lot", + "quick_cache", + "ringbuf", + "serde", + "serde_cbor", + "sysdefs", +] + [[package]] name = "rcrt1" version = "2.5.0" @@ -3019,6 +3222,15 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "ringbuf" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f65af18d50f789e74aaf23bbb3f65dcd22a3cb6e029b5bced149f6bd57c5c2a2" +dependencies = [ + "cache-padded", +] + [[package]] name = "rsa" version = "0.9.7" @@ -3275,6 +3487,17 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_cbor" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7081ed758ec726a6ed8ee7e92f5d3f6e6f8c3901b1f972e3a4a2f2599fad14f" +dependencies = [ + "byteorder", + "half", + "serde", +] + [[package]] name = "serde_derive" version = "1.0.217" @@ -3637,6 +3860,13 @@ dependencies = [ "syn 2.0.98", ] +[[package]] +name = "sysdefs" +version = "0.1.0" +dependencies = [ + "libc", +] + [[package]] name = "system-interface" version = "0.27.3" @@ -4019,9 +4249,7 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasi-common" -version = "23.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ddca85a537113179aae69f1faf916401113acb66e4b52b86483344bc5ae43fa" +version = "23.0.0" dependencies = [ "anyhow", "bitflags 2.8.0", @@ -4032,14 +4260,15 @@ dependencies = [ "fs-set-times", "io-extras 0.18.4", "io-lifetimes 2.0.4", + "libc", "log", "once_cell", "rustix 0.38.44", "system-interface", "thiserror", "tracing", - "wasmtime", - "wiggle", + "wasmtime 23.0.0", + "wiggle 23.0.0", "windows-sys 0.52.0", ] @@ -4101,6 +4330,15 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "wasm-encoder" +version = "0.211.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e7d931a1120ef357f32b74547646b6fa68ea25e377772b72874b131a9ed70d4" +dependencies = [ + "leb128", +] + [[package]] name = "wasm-encoder" version = "0.212.0" @@ -4120,6 +4358,20 @@ dependencies = [ "wasmparser 0.225.0", ] +[[package]] +name = "wasmparser" +version = "0.211.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3189cc8a91f547390e2f043ca3b3e3fe0892f7d581767fd4e4b7f3dc3fe8e561" +dependencies = [ + "ahash", + "bitflags 2.8.0", + "hashbrown 0.14.5", + "indexmap", + "semver", + "serde", +] + [[package]] name = "wasmparser" version = "0.212.0" @@ -4144,6 +4396,17 @@ dependencies = [ "indexmap", ] +[[package]] +name = "wasmprinter" +version = "0.211.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23708dd7a986bd9b12fca26eff525bbc3659a336e947fd9ed9fdf79086825aec" +dependencies = [ + "anyhow", + "termcolor", + "wasmparser 0.211.1", +] + [[package]] name = "wasmprinter" version = "0.212.0" @@ -4155,6 +4418,47 @@ dependencies = [ "wasmparser 0.212.0", ] +[[package]] +name = "wasmtime" +version = "23.0.0" +dependencies = [ + "anyhow", + "bitflags 2.8.0", + "bumpalo", + "cc", + "cfg-if 1.0.0", + "hashbrown 0.14.5", + "indexmap", + "libc", + "libm", + "log", + "mach2", + "memfd", + "object", + "once_cell", + "paste", + "postcard", + "psm", + "rawposix", + "rustix 0.38.44", + "serde", + "serde_derive", + "smallvec", + "sptr", + "sysdefs", + "target-lexicon", + "wasmparser 0.211.1", + "wasmtime-asm-macros 23.0.0", + "wasmtime-component-macro 23.0.0", + "wasmtime-cranelift 23.0.0", + "wasmtime-environ 23.0.0", + "wasmtime-jit-icache-coherence 23.0.0", + "wasmtime-lind-utils", + "wasmtime-slab 23.0.0", + "wasmtime-versioned-export-macros 23.0.0", + "windows-sys 0.52.0", +] + [[package]] name = "wasmtime" version = "23.0.3" @@ -4188,19 +4492,26 @@ dependencies = [ "sptr", "target-lexicon", "wasmparser 0.212.0", - "wasmtime-asm-macros", - "wasmtime-component-macro", - "wasmtime-component-util", - "wasmtime-cranelift", - "wasmtime-environ", + "wasmtime-asm-macros 23.0.3", + "wasmtime-component-macro 23.0.3", + "wasmtime-component-util 23.0.3", + "wasmtime-cranelift 23.0.3", + "wasmtime-environ 23.0.3", "wasmtime-fiber", - "wasmtime-jit-icache-coherence", - "wasmtime-slab", - "wasmtime-versioned-export-macros", + "wasmtime-jit-icache-coherence 23.0.3", + "wasmtime-slab 23.0.3", + "wasmtime-versioned-export-macros 23.0.3", "wasmtime-winch", "windows-sys 0.52.0", ] +[[package]] +name = "wasmtime-asm-macros" +version = "23.0.0" +dependencies = [ + "cfg-if 1.0.0", +] + [[package]] name = "wasmtime-asm-macros" version = "23.0.3" @@ -4210,6 +4521,19 @@ dependencies = [ "cfg-if 1.0.0", ] +[[package]] +name = "wasmtime-component-macro" +version = "23.0.0" +dependencies = [ + "anyhow", + "proc-macro2", + "quote", + "syn 2.0.98", + "wasmtime-component-util 23.0.0", + "wasmtime-wit-bindgen 23.0.0", + "wit-parser 0.211.1", +] + [[package]] name = "wasmtime-component-macro" version = "23.0.3" @@ -4220,17 +4544,43 @@ dependencies = [ "proc-macro2", "quote", "syn 2.0.98", - "wasmtime-component-util", - "wasmtime-wit-bindgen", - "wit-parser", + "wasmtime-component-util 23.0.3", + "wasmtime-wit-bindgen 23.0.3", + "wit-parser 0.212.0", ] +[[package]] +name = "wasmtime-component-util" +version = "23.0.0" + [[package]] name = "wasmtime-component-util" version = "23.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71a40200d42a8985edadb4007a0ed320756cbe28065b83e0027e39524c1b1b22" +[[package]] +name = "wasmtime-cranelift" +version = "23.0.0" +dependencies = [ + "anyhow", + "cfg-if 1.0.0", + "cranelift-codegen 0.110.0", + "cranelift-control 0.110.0", + "cranelift-entity 0.110.0", + "cranelift-frontend 0.110.0", + "cranelift-native 0.110.0", + "cranelift-wasm 0.110.0", + "gimli 0.28.1", + "log", + "object", + "target-lexicon", + "thiserror", + "wasmparser 0.211.1", + "wasmtime-environ 23.0.0", + "wasmtime-versioned-export-macros 23.0.0", +] + [[package]] name = "wasmtime-cranelift" version = "23.0.3" @@ -4239,20 +4589,41 @@ checksum = "b099ef9b7808fa8d18cad32243e78e9c07a4a8aacfa913d88dc08704b1643c49" dependencies = [ "anyhow", "cfg-if 1.0.0", - "cranelift-codegen", - "cranelift-control", - "cranelift-entity", - "cranelift-frontend", - "cranelift-native", - "cranelift-wasm", + "cranelift-codegen 0.110.3", + "cranelift-control 0.110.3", + "cranelift-entity 0.110.3", + "cranelift-frontend 0.110.3", + "cranelift-native 0.110.3", + "cranelift-wasm 0.110.3", "gimli 0.28.1", "log", "object", "target-lexicon", "thiserror", "wasmparser 0.212.0", - "wasmtime-environ", - "wasmtime-versioned-export-macros", + "wasmtime-environ 23.0.3", + "wasmtime-versioned-export-macros 23.0.3", +] + +[[package]] +name = "wasmtime-environ" +version = "23.0.0" +dependencies = [ + "anyhow", + "cranelift-bitset 0.110.0", + "cranelift-entity 0.110.0", + "gimli 0.28.1", + "indexmap", + "log", + "object", + "postcard", + "serde", + "serde_derive", + "target-lexicon", + "wasm-encoder 0.211.1", + "wasmparser 0.211.1", + "wasmprinter 0.211.1", + "wasmtime-types 23.0.0", ] [[package]] @@ -4262,8 +4633,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2f1765f6ca1a166927bee13ad4aed7bf18269f34c0cd7d6d523889a0b52e6ee" dependencies = [ "anyhow", - "cranelift-bitset", - "cranelift-entity", + "cranelift-bitset 0.110.3", + "cranelift-entity 0.110.3", "gimli 0.28.1", "indexmap", "log", @@ -4275,9 +4646,9 @@ dependencies = [ "target-lexicon", "wasm-encoder 0.212.0", "wasmparser 0.212.0", - "wasmprinter", - "wasmtime-component-util", - "wasmtime-types", + "wasmprinter 0.212.0", + "wasmtime-component-util 23.0.3", + "wasmtime-types 23.0.3", ] [[package]] @@ -4290,8 +4661,18 @@ dependencies = [ "cc", "cfg-if 1.0.0", "rustix 0.38.44", - "wasmtime-asm-macros", - "wasmtime-versioned-export-macros", + "wasmtime-asm-macros 23.0.3", + "wasmtime-versioned-export-macros 23.0.3", + "windows-sys 0.52.0", +] + +[[package]] +name = "wasmtime-jit-icache-coherence" +version = "23.0.0" +dependencies = [ + "anyhow", + "cfg-if 1.0.0", + "libc", "windows-sys 0.52.0", ] @@ -4307,12 +4688,64 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "wasmtime-lind-common" +version = "23.0.0" +dependencies = [ + "anyhow", + "log", + "rand 0.8.5", + "rawposix", + "wasmtime 23.0.0", + "wasmtime-environ 23.0.0", + "wasmtime-lind-multi-process", +] + +[[package]] +name = "wasmtime-lind-multi-process" +version = "23.0.0" +dependencies = [ + "anyhow", + "log", + "rand 0.8.5", + "rawposix", + "sysdefs", + "wasi-common", + "wasmtime 23.0.0", + "wasmtime-environ 23.0.0", + "wasmtime-lind-utils", +] + +[[package]] +name = "wasmtime-lind-utils" +version = "23.0.0" +dependencies = [ + "anyhow", + "log", +] + +[[package]] +name = "wasmtime-slab" +version = "23.0.0" + [[package]] name = "wasmtime-slab" version = "23.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f92a137c17c992eb5eaacfa0f0590353471e49dbb4bdbdf9cf7536d66109e63a" +[[package]] +name = "wasmtime-types" +version = "23.0.0" +dependencies = [ + "anyhow", + "cranelift-entity 0.110.0", + "serde", + "serde_derive", + "smallvec", + "wasmparser 0.211.1", +] + [[package]] name = "wasmtime-types" version = "23.0.3" @@ -4320,13 +4753,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a6072ac3267866d99ca726b6a4f157df9b733aac8082e902d527368f07c303ba" dependencies = [ "anyhow", - "cranelift-entity", + "cranelift-entity 0.110.3", "serde", "serde_derive", "smallvec", "wasmparser 0.212.0", ] +[[package]] +name = "wasmtime-versioned-export-macros" +version = "23.0.0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.98", +] + [[package]] name = "wasmtime-versioned-export-macros" version = "23.0.3" @@ -4364,11 +4806,23 @@ dependencies = [ "tokio", "tracing", "url", - "wasmtime", - "wiggle", + "wasmtime 23.0.3", + "wiggle 23.0.3", "windows-sys 0.52.0", ] +[[package]] +name = "wasmtime-wasi-threads" +version = "23.0.0" +dependencies = [ + "anyhow", + "log", + "rand 0.8.5", + "wasi-common", + "wasmtime 23.0.0", + "wasmtime-environ 23.0.0", +] + [[package]] name = "wasmtime-winch" version = "23.0.3" @@ -4376,16 +4830,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "beb1abdc26ddf1d7c819ea0fcbfccb0808410549d28bb3154c9bdb7d11fbcc58" dependencies = [ "anyhow", - "cranelift-codegen", + "cranelift-codegen 0.110.3", "gimli 0.28.1", "object", "target-lexicon", "wasmparser 0.212.0", - "wasmtime-cranelift", - "wasmtime-environ", + "wasmtime-cranelift 23.0.3", + "wasmtime-environ 23.0.3", "winch-codegen", ] +[[package]] +name = "wasmtime-wit-bindgen" +version = "23.0.0" +dependencies = [ + "anyhow", + "heck 0.4.1", + "indexmap", + "wit-parser 0.211.1", +] + [[package]] name = "wasmtime-wit-bindgen" version = "23.0.3" @@ -4395,7 +4859,7 @@ dependencies = [ "anyhow", "heck 0.4.1", "indexmap", - "wit-parser", + "wit-parser 0.212.0", ] [[package]] @@ -4464,6 +4928,19 @@ version = "0.25.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" +[[package]] +name = "wiggle" +version = "23.0.0" +dependencies = [ + "anyhow", + "async-trait", + "bitflags 2.8.0", + "thiserror", + "tracing", + "wasmtime 23.0.0", + "wiggle-macro 23.0.0", +] + [[package]] name = "wiggle" version = "23.0.3" @@ -4475,8 +4952,21 @@ dependencies = [ "bitflags 2.8.0", "thiserror", "tracing", - "wasmtime", - "wiggle-macro", + "wasmtime 23.0.3", + "wiggle-macro 23.0.3", +] + +[[package]] +name = "wiggle-generate" +version = "23.0.0" +dependencies = [ + "anyhow", + "heck 0.4.1", + "proc-macro2", + "quote", + "shellexpand", + "syn 2.0.98", + "witx", ] [[package]] @@ -4494,6 +4984,16 @@ dependencies = [ "witx", ] +[[package]] +name = "wiggle-macro" +version = "23.0.0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.98", + "wiggle-generate 23.0.0", +] + [[package]] name = "wiggle-macro" version = "23.0.3" @@ -4503,7 +5003,7 @@ dependencies = [ "proc-macro2", "quote", "syn 2.0.98", - "wiggle-generate", + "wiggle-generate 23.0.3", ] [[package]] @@ -4544,14 +5044,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a666bf2cdb838e68b9b8370d7ebf8806b87ccc0d89a634bfc9ed8ffca1f19591" dependencies = [ "anyhow", - "cranelift-codegen", + "cranelift-codegen 0.110.3", "gimli 0.28.1", "regalloc2", "smallvec", "target-lexicon", "wasmparser 0.212.0", - "wasmtime-cranelift", - "wasmtime-environ", + "wasmtime-cranelift 23.0.3", + "wasmtime-environ 23.0.3", ] [[package]] @@ -4787,6 +5287,24 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "wit-parser" +version = "0.211.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3cc90c50c7ec8a824b5d2cddddff13b2dc12b7a96bf8684d11474223c2ea22f" +dependencies = [ + "anyhow", + "id-arena", + "indexmap", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser 0.211.1", +] + [[package]] name = "wit-parser" version = "0.212.0" diff --git a/Cargo.toml b/Cargo.toml index 638375a8e..aa77c7e0b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -229,10 +229,15 @@ zeroize = { version = "1.5.4", features = ["alloc"], default-features = false } # wasmtime and its pinned dependencies # these will need to be updated together -wasmtime = { version = "23.0.0", features = ["cranelift", "pooling-allocator", "gc", "threads"], default-features = false } +wasmtime = { path = "../lind-wasm/src/wasmtime/crates/wasmtime", features = ["cranelift", "pooling-allocator", "gc", "threads"], default-features = false } +wasmtime-lind-common = { path = "../lind-wasm/src/wasmtime/crates/lind-common" } +wasmtime-lind-multi-process = { path = "../lind-wasm/src/wasmtime/crates/lind-multi-process" } +wasmtime-lind-utils = { path = "../lind-wasm/src/wasmtime/crates/lind-utils" } +wasmtime-wasi-threads = { path = "../lind-wasm/src/wasmtime/crates/wasi-threads" } +rawposix = { path = "../lind-wasm/src/wasmtime/crates/rawposix" } cap-std = { version = "3.4.2", default-features = false } io-lifetimes = { version = "2.0.4", default-features = false } rustix = { version = "0.38.44", features = ["std"], default-features = false } -wasi-common = { version = "23.0.0", features = ["sync"] ,default-features = false } +wasi-common = { path = "../lind-wasm/src/wasmtime/crates/wasi-common", features = ["sync"] ,default-features = false } wasmtime-wasi = { version = "23.0.0", features = ["preview1"] , default-features = false } wiggle = { version = "23.0.0", default-features = false } diff --git a/crates/exec-wasmtime/Cargo.toml b/crates/exec-wasmtime/Cargo.toml index 084986a44..ab3138a2f 100644 --- a/crates/exec-wasmtime/Cargo.toml +++ b/crates/exec-wasmtime/Cargo.toml @@ -39,6 +39,11 @@ webpki-roots = { workspace = true } wiggle = { workspace = true, features = ["tracing_log"] } x509-cert = { workspace = true } zeroize = { workspace = true } +wasmtime-lind-common = { workspace = true } +wasmtime-lind-multi-process = { workspace = true } +wasmtime-lind-utils = { workspace = true } +rawposix = { workspace = true } +wasmtime-wasi-threads = { workspace = true } [target.'cfg(windows)'.dependencies] io-extras = { workspace = true } diff --git a/crates/exec-wasmtime/src/lib.rs b/crates/exec-wasmtime/src/lib.rs index cf56f6644..d477f83ce 100644 --- a/crates/exec-wasmtime/src/lib.rs +++ b/crates/exec-wasmtime/src/lib.rs @@ -10,7 +10,6 @@ mod log; mod runtime; mod workload; -mod lind; #[cfg(unix)] pub use log::Level as LogLevel; diff --git a/crates/exec-wasmtime/src/lind.rs b/crates/exec-wasmtime/src/lind.rs deleted file mode 100644 index 878a0e915..000000000 --- a/crates/exec-wasmtime/src/lind.rs +++ /dev/null @@ -1,23 +0,0 @@ -use anyhow::{Result, Context}; -use lind_wasm::cli::RunCommand; -use clap::Parser; -use std::fs::File; -use std::io::Write; -use tempfile::NamedTempFile; - -pub fn execute_wasm(wasm_bytes: &[u8], args: &[String]) -> Result { - - let mut file = NamedTempFile::new() - .context("failed to create temporary wasm file")?; - file.write_all(wasm_bytes) - .context("failed to write wasm to temporary file")?; - let path = file.path().to_string_lossy().to_string(); - - let mut argv = vec!["wasmtime run --wasi threads=y --wasi preview2=n".to_string(), path]; - argv.extend(args.iter().cloned()); - - let cmd = RunCommand::parse_from(argv); - cmd.execute().context("lind-wasm execution failed")?; - - Ok(0) -} diff --git a/crates/exec-wasmtime/src/runtime/mod.rs b/crates/exec-wasmtime/src/runtime/mod.rs index 9db3e432e..d3cfc0ca6 100644 --- a/crates/exec-wasmtime/src/runtime/mod.rs +++ b/crates/exec-wasmtime/src/runtime/mod.rs @@ -7,108 +7,586 @@ mod io; //mod net; use self::io::null::Null; -use self::io::stdio_file; +// use self::io::stdio_file; //use self::net::{connect_file, listen_file}; -use super::{Package, Workload, execute_wasm}; +use super::{Package, Workload}; + +use wasmtime_lind_common::LindCommonCtx; +use wasmtime_lind_multi_process::{LindCtx, LindHost, CAGE_START_ID, THREAD_START_ID}; +use wasmtime_lind_utils::lind_syscall_numbers::EXIT_SYSCALL; +use wasmtime_lind_utils::LindCageManager; +use rawposix::safeposix::dispatcher::lind_syscall_api; +use std::sync::Arc; +use cap_std::fs::Dir; +use wasmtime_wasi_threads::WasiThreadsCtx; +use std::sync::atomic::AtomicU64; +use anyhow::{anyhow, Result, bail}; +use wasmtime::{ + Func, InstantiateType, StoreLimits, ValType, +}; use anyhow::Context; use enarx_config::{Config, File}; -use wasi_common::snapshots::preview_1::types::Rights; -use wasi_common::WasiFile; +// use wasi_common::snapshots::preview_1::types::Rights; +// use wasi_common::WasiFile; use wasmtime::{AsContextMut, Engine, Linker, Module, Store, Val}; -use wasmtime_wasi::{Stderr, Stdin, Stdout, StdoutStream, StdinStream, DirPerms, FilePerms}; -use wasmtime_wasi::WasiCtxBuilder; -use std::fs; -use wasmtime_wasi::preview1::{add_to_linker_sync, WasiP1Ctx}; -use wiggle::tracing::{instrument, trace_span}; +// use wasmtime_wasi::{Stderr, Stdin, Stdout, StdoutStream, StdinStream, DirPerms, FilePerms}; +// use wasmtime_wasi::WasiCtxBuilder; +use wasi_common::sync::WasiCtxBuilder; +// use std::fs; +// use wasmtime_wasi::preview1::{add_to_linker_sync, WasiP1Ctx}; +// use wasmtime_wasi::{add_to_linker, WasiCtxBuilder}; +// use wiggle::tracing::{instrument, trace_span}; +use wiggle::tracing::trace_span; + +// Declare the context +#[derive(Default, Clone)] +struct MyCtx { + preview1_ctx: Option, + wasi_threads: Option>>, + lind_common_ctx: Option, + lind_fork_ctx: Option>>, +} + +impl AsMut for MyCtx { + fn as_mut(&mut self) -> &mut wasi_common::WasiCtx { + self.preview1_ctx + .as_mut() + .expect("preview1_ctx must be initialized before use") + } +} + +impl MyCtx { + pub fn fork(&self) -> Self { + // we want to do a real fork for wasi_preview1 context since glibc uses the environment variable + // related interface here + let forked_preview1_ctx = match &self.preview1_ctx { + Some(ctx) => Some(ctx.fork()), + None => None + }; + + // and we also want to fork the lind-common context and lind-multi-process context + let forked_lind_fork_ctx = match &self.lind_fork_ctx { + Some(ctx) => Some(ctx.fork()), + None => None + }; + + let forked_lind_common_ctx = match &self.lind_common_ctx { + Some(ctx) => Some(ctx.fork()), + None => None + }; + + // besides preview1_ctx, lind_common_ctx and forked_lind_fork_ctx, we do not + // care about other context since they are not used by glibc so we can just share + // them between processes + let forked_host = Self { + preview1_ctx: forked_preview1_ctx, + lind_fork_ctx: forked_lind_fork_ctx, + lind_common_ctx: forked_lind_common_ctx, + wasi_threads: self.wasi_threads.clone(), + }; + + return forked_host; + } +} + +impl LindHost> for MyCtx { + fn get_ctx(&self) -> LindCtx> { + self.lind_fork_ctx.clone().unwrap() + } +} // The Enarx Wasm runtime +#[derive(Clone)] pub struct Runtime; impl Runtime { // Execute an Enarx [Package] - #[instrument] + // #[instrument] pub fn execute(package: Package) -> anyhow::Result> { - // let (prvkey, crtreq) = - // identity::generate().context("failed to generate a private key and CSR")?; - - // let Workload { webasm, config } = package.try_into()?; - // let Config { - // steward, - // args, - // files, - // env, - // } = config.unwrap_or_default(); - - // let certs = if let Some(url) = steward { - // identity::steward(&url, crtreq).context("failed to attest to Steward")? - // } else { - // identity::selfsigned(&prvkey).context("failed to generate self-signed certificates")? - // } - // .into_iter() - // .map(rustls::Certificate) - // .collect::>(); - - // let mut config = wasmtime::Config::new(); - // // config.wasm_reference_types(true); // Enable reference types - // // config.wasm_function_references(true); // Enable function references - // // config.wasm_gc(true); // Enable garbage collection - // config.wasm_backtrace(true); - // config.native_unwind_info(true); // Enable threads - // config.debug_info(true); // Enable debug info - // config.memory_init_cow(false); - // config.async_support(false); - - // let engine = trace_span!("initialize Wasmtime engine") - // .in_scope(|| Engine::new(&config)) - // .context("failed to create execution engine")?; - - // let mut linker = trace_span!("setup linker").in_scope(|| Linker::new(&engine)); - // trace_span!("link WASI") - // .in_scope(|| add_to_linker_sync(&mut linker, |s| s)) - // .context("failed to setup linker and link WASI")?; - - // let mut builder = WasiCtxBuilder::new(); - // builder.inherit_stdio(); - // builder.inherit_stdin(); - // builder.inherit_stderr(); - // // builder.args(&["main.wasm", "/etc/resolv.conf", "/etc/resolv.conf"]); - // builder.preopened_dir("/home", ".", DirPerms::all(), FilePerms::all()).expect("failed to open current directory"); - // // builder.preopened_dir("/tmp", "/tmp", DirPerms::all(), FilePerms::all()).expect("failed to open current directory"); - - // //fs::File::open("/home/lind/enarx/test.txt").map_err(|err| format!("error opening input fuckup /home/lind/enarx/test.txt: {}", err)).unwrap(); - - // let mut wstore = trace_span!("initialize Wasmtime store") - // .in_scope(|| Store::new(&engine, builder.build_p1())); - - // let module = trace_span!("compile Wasm") - // .in_scope(|| Module::from_binary(&engine, &webasm)) - // .context("failed to compile Wasm module")?; - // trace_span!("link Wasm") - // .in_scope(|| linker.module(&mut wstore, "", &module)) - // .context("failed to link module")?; - - // let mut ctx = wstore.as_context_mut(); - // let ctx = ctx.data_mut(); - - // let func = trace_span!("get default function") - // .in_scope(|| linker.get_default(&mut wstore, "")) - // .context("failed to get default function")?; - - // let mut values = vec![Val::null_any_ref(); func.ty(&wstore).results().len()]; - // trace_span!("execute default function") - // .in_scope(|| func.call(wstore, Default::default(), &mut values)) - // .context("failed to execute default function")?; - // Ok(values) + let (prvkey, crtreq) = + identity::generate().context("failed to generate a private key and CSR")?; + let Workload { webasm, config } = package.try_into()?; - let args = config - .as_ref() - .map(|cfg| cfg.args.clone()) - .unwrap_or_default(); - - let exit_code = execute_wasm(&webasm, &args)?; - Ok(vec![Val::I32(exit_code)]) - + let enarx_conf = config; + let Config { + steward, + args, + files, + env, + } = enarx_conf.clone().unwrap_or_default(); + + let certs = if let Some(url) = steward { + // Obtaining attestation certificates + identity::steward(&url, crtreq).context("failed to attest to Steward")? + } else { + // Generating a self-signed certificate + identity::selfsigned(&prvkey).context("failed to generate self-signed certificates")? + } + .into_iter() + .map(rustls::Certificate) + .collect::>(); + + let mut config = wasmtime::Config::new(); + // config.wasm_reference_types(true); // Enable reference types + // config.wasm_function_references(true); // Enable function references + // config.wasm_gc(true); // Enable garbage collection + config.wasm_backtrace(true); + config.native_unwind_info(true); // Enable threads + config.debug_info(true); // Enable debug info + config.memory_init_cow(false); + // config.async_support(false); + + let engine = trace_span!("initialize Wasmtime engine") + .in_scope(|| Engine::new(&config)) + .context("failed to create execution engine")?; + + // let wasi = builder.build(); + let Host = MyCtx::default(); + + // let mut wstore = trace_span!("initialize Wasmtime store") + // .in_scope(|| Store::new(&engine, builder.build_p1())); + let mut wstore = trace_span!("initialize Wasmtime store") + .in_scope(|| Store::new(&engine, Host)); + + let module = trace_span!("compile Wasm") + .in_scope(|| Module::from_binary(&engine, &webasm)) + .context("failed to compile Wasm module")?; + + let lind_manager = Arc::new(LindCageManager::new(0)); + rawposix::safeposix::dispatcher::lindrustinit(0); + lind_manager.increment(); + + // Set up the WASI. In lind-wasm, we predefine all the features we need are `thread` and `wasipreview1` + // so we manually add them to the linker without checking the input + let mut linker = trace_span!("setup linker").in_scope(|| Linker::new(&engine)); + // Setup WASI-p1 + trace_span!("link WASI") + .in_scope(|| wasi_common::sync::add_to_linker(&mut linker, |s: &mut MyCtx| AsMut::::as_mut(s))) + .context("failed to setup linker and link WASI")?; + let mut builder = WasiCtxBuilder::new(); + builder.inherit_stdio(); + builder.inherit_stdin(); + builder.inherit_stderr(); + // builder.preopened_dir("/home", ".", DirPerms::all(), FilePerms::all()).expect("failed to open current directory"); + let dir = Dir::open_ambient_dir("/home", cap_std::ambient_authority()).expect("failed to open /home"); + builder.preopened_dir(dir, ".").expect("failed to open current directory"); + wstore.data_mut().preview1_ctx = Some(builder.build()); + + // Setup WASI-thread + trace_span!("link WASI-thread") + .in_scope(|| wasmtime_wasi_threads::add_to_linker(&mut linker, &wstore, &module, |s: &mut MyCtx| s.wasi_threads.as_ref().unwrap())) + .context("failed to setup linker and link WASI")?; + + // attach Lind-Common-Context to the host + let shared_next_cageid = Arc::new(AtomicU64::new(1)); + { + wasmtime_lind_common::add_to_linker::>(&mut linker, |host| { + host.lind_common_ctx.as_ref().unwrap() + })?; + wstore.data_mut().lind_common_ctx = Some(LindCommonCtx::new(shared_next_cageid.clone())?); + } + + // attach Lind-Multi-Process-Context to the host + { + wstore.data_mut().lind_fork_ctx = Some(LindCtx::new( + module.clone(), + linker.clone(), + lind_manager.clone(), + // self.clone(), + webasm.clone(), + enarx_conf.clone(), + shared_next_cageid.clone(), + |host| host.lind_fork_ctx.as_mut().unwrap(), + |host| host.fork(), + |webasm, enarx_conf, path, args, pid, next_cageid, lind_manager, envs| { + Runtime::execute_with_lind( + webasm.clone(), + enarx_conf.clone(), + lind_manager.clone(), + pid as u64, + next_cageid.clone(), + ) + }, + )?); + } + + wstore.data_mut().wasi_threads = Some(Arc::new(WasiThreadsCtx::new( + module.clone(), + Arc::new(linker.clone()), + )?)); + + let result = wasmtime_wasi::runtime::with_ambient_tokio_runtime(|| { + Runtime::load_main_module( + &mut wstore, + &mut linker, + &module, + CAGE_START_ID as u64, + &args, + ) + .with_context(|| { + format!( + "failed to run main module" + ) + }) + }); + + match result { + Ok(ref res) => { + let mut code = 0; + let retval: &Val = res.get(0).unwrap(); + if let Val::I32(res) = retval { + code = *res; + } + // exit the thread + // if rawposix::interface::lind_thread_exit( + // CAGE_START_ID as u64, + // THREAD_START_ID as u64, + // ) { + // // we clean the cage only if this is the last thread in the cage + // // exit the cage with the exit code + // lind_syscall_api(1, EXIT_SYSCALL as u32, 0, code as u64, 0, 0, 0, 0, 0); + + // // main cage exits + // lind_manager.decrement(); + // } + // we clean the cage only if this is the last thread in the cage + // exit the cage with the exit code + lind_syscall_api(1, EXIT_SYSCALL as u32, 0, code as u64, 0, 0, 0, 0, 0); + + // main cage exits + lind_manager.decrement(); + + // we wait until all other cage exits + lind_manager.wait(); + // after all cage exits, finalize the lind + rawposix::safeposix::dispatcher::lindrustfinalize(); + } + Err(e) => { + // Exit the process if Wasmtime understands the error; + // otherwise, fall back on Rust's default error printing/return + // code. + return Err(wasi_common::maybe_exit_on_error(e)); + } + } + + result + } + + pub fn execute_with_lind( + // Wasm module + webasm: Vec, + // Enarx keep configuration + config: Option, + lind_manager: Arc, + pid: u64, + next_cageid: Arc, + ) -> Result> { + let enarx_conf = config; + let Config { + steward, + args, + files, + env, + } = enarx_conf.clone().unwrap_or_default(); + + let mut config = wasmtime::Config::new(); + // config.wasm_reference_types(true); // Enable reference types + // config.wasm_function_references(true); // Enable function references + // config.wasm_gc(true); // Enable garbage collection + config.wasm_backtrace(true); + config.native_unwind_info(true); // Enable threads + config.debug_info(true); // Enable debug info + config.memory_init_cow(false); + // config.async_support(false); + + let engine = trace_span!("initialize Wasmtime engine") + .in_scope(|| Engine::new(&config)) + .context("failed to create execution engine")?; + + // let wasi = builder.build(); + let Host = MyCtx::default(); + + // let mut wstore = trace_span!("initialize Wasmtime store") + // .in_scope(|| Store::new(&engine, builder.build_p1())); + let mut wstore = trace_span!("initialize Wasmtime store") + .in_scope(|| Store::new(&engine, Host)); + + let module = trace_span!("compile Wasm") + .in_scope(|| Module::from_binary(&engine, &webasm)) + .context("failed to compile Wasm module")?; + + // Set up the WASI. In lind-wasm, we predefine all the features we need are `thread` and `wasipreview1` + // so we manually add them to the linker without checking the input + let mut linker = trace_span!("setup linker").in_scope(|| Linker::new(&engine)); + // Setup WASI-p1 + trace_span!("link WASI") + .in_scope(|| wasi_common::sync::add_to_linker(&mut linker, |s: &mut MyCtx| AsMut::::as_mut(s))) + .context("failed to setup linker and link WASI")?; + let mut builder = WasiCtxBuilder::new(); + builder.inherit_stdio(); + builder.inherit_stdin(); + builder.inherit_stderr(); + // builder.preopened_dir("/home", ".", DirPerms::all(), FilePerms::all()).expect("failed to open current directory"); + let dir = Dir::open_ambient_dir("/home", cap_std::ambient_authority()).expect("failed to open /home"); + builder.preopened_dir(dir, ".").expect("failed to open current directory"); + wstore.data_mut().preview1_ctx = Some(builder.build()); + + // Setup WASI-thread + trace_span!("link WASI-thread") + .in_scope(|| wasmtime_wasi_threads::add_to_linker(&mut linker, &wstore, &module, |s: &mut MyCtx| s.wasi_threads.as_ref().unwrap())) + .context("failed to setup linker and link WASI")?; + + // attach Lind-Common-Context to the host + let shared_next_cageid = Arc::new(AtomicU64::new(1)); + { + wasmtime_lind_common::add_to_linker::>(&mut linker, |host| { + host.lind_common_ctx.as_ref().unwrap() + })?; + // Create a new lind ctx with the next cage ID since we are going to fork + wstore.data_mut().lind_common_ctx = Some(LindCommonCtx::new_with_pid( + pid as i32, + next_cageid.clone(), + )?); + } + + // attach Lind-Multi-Process-Context to the host + { + wstore.data_mut().lind_fork_ctx = Some(LindCtx::new( + module.clone(), + linker.clone(), + lind_manager.clone(), + // self.clone(), + webasm.clone(), + enarx_conf.clone(), + shared_next_cageid.clone(), + |host| host.lind_fork_ctx.as_mut().unwrap(), + |host| host.fork(), + |webasm, enarx_conf, path, args, pid, next_cageid, lind_manager, envs| { + Runtime::execute_with_lind( + webasm.clone(), + enarx_conf.clone(), + lind_manager.clone(), + pid as u64, + next_cageid.clone(), + ) + }, + )?); + wstore.data_mut().lind_fork_ctx = Some(LindCtx::new_with_pid( + module.clone(), + linker.clone(), + lind_manager.clone(), + // self.clone(), + webasm.clone(), + enarx_conf.clone(), + pid as i32, + next_cageid.clone(), + |host| host.lind_fork_ctx.as_mut().unwrap(), + |host| host.fork(), + |webasm, enarx_conf, path, args, pid, next_cageid, lind_manager, envs| { + Runtime::execute_with_lind( + webasm.clone(), + enarx_conf.clone(), + lind_manager.clone(), + pid as u64, + next_cageid.clone(), + ) + }, + )?); + } + + wstore.data_mut().wasi_threads = Some(Arc::new(WasiThreadsCtx::new( + module.clone(), + Arc::new(linker.clone()), + )?)); + + let result = wasmtime_wasi::runtime::with_ambient_tokio_runtime(|| { + Runtime::load_main_module( + &mut wstore, + &mut linker, + &module, + pid as u64, + &args, + ) + .with_context(|| { + format!( + "failed to run main module" + ) + }) + }); + + result + } + + fn load_main_module( + store: &mut Store, + linker: &mut Linker, + module: &Module, + pid: u64, + args: &[String], + ) -> Result> { + let instance = linker + .instantiate_with_lind( + &mut *store, + &module, + InstantiateType::InstantiateFirst(pid), + ) + .context(format!( + "failed to instantiate" + ))?; + + // If `_initialize` is present, meaning a reactor, then invoke + // the function. + if let Some(func) = instance.get_func(&mut *store, "_initialize") { + func.typed::<(), ()>(&store)?.call(&mut *store, ())?; + } + + // Look for the specific function provided or otherwise look for + // "" or "_start" exports to run as a "main" function. + let func = instance + .get_func(&mut *store, "") + .or_else(|| instance.get_func(&mut *store, "_start")); + + let stack_low = instance.get_stack_low(store.as_context_mut()).unwrap(); + let stack_pointer = instance.get_stack_pointer(store.as_context_mut()).unwrap(); + store.as_context_mut().set_stack_base(stack_pointer as u64); + store.as_context_mut().set_stack_top(stack_low as u64); + + // retrieve the epoch global + // let lind_epoch = instance + // .get_export(&mut *store, "epoch") + // .and_then(|export| export.into_global()) + // .expect("Failed to find epoch global export!"); + + // // retrieve the handler (underlying pointer) for the epoch global + // let pointer = lind_epoch.get_handler(&mut *store); + + // // initialize the signal for the main thread of the cage + // rawposix::interface::lind_signal_init( + // pid, + // pointer as *mut u64, + // THREAD_START_ID, + // true, /* this is the main thread */ + // ); + + // // see comments at signal_may_trigger for more details + // rawposix::interface::signal_may_trigger(pid); + + let result = match func { + Some(func) => Runtime::invoke_func(store, func, &args), + None => Ok(vec![]), + }; + result + } + + fn invoke_func(store: &mut Store, func: Func, args: &[String]) -> Result> { + let ty = func.ty(&store); + if ty.params().len() > 0 { + eprintln!( + "warning: using `--invoke` with a function that takes arguments \ + is experimental and may break in the future" + ); + } + // let mut args = self.module_and_args.iter().skip(1); + let mut args = args.iter(); + let mut values = Vec::new(); + for ty in ty.params() { + let val_str = args + .next() + .ok_or_else(|| anyhow!("not enough arguments for invoke"))?; + let val = match ty { + ValType::I32 => Val::I32(val_str.parse()?), + ValType::I64 => Val::I64(val_str.parse()?), + ValType::F32 => Val::F32(val_str.parse::()?.to_bits()), + ValType::F64 => Val::F64(val_str.parse::()?.to_bits()), + _ => bail!("unsupported argument type {:?}", ty), + }; + values.push(val); + } + + // Invoke the function and then afterwards print all the results that came + // out, if there are any. + let mut results = vec![Val::null_func_ref(); ty.results().len()]; + func.call(&mut *store, &values, &mut results) + .with_context(|| { format!("failed to invoke command default") }); + + Ok(results) } + + } +// #[instrument] +// pub fn execute(package: Package) -> anyhow::Result> { +// let (prvkey, crtreq) = +// identity::generate().context("failed to generate a private key and CSR")?; + +// let Workload { webasm, config } = package.try_into()?; +// let Config { +// steward, +// args, +// files, +// env, +// } = config.unwrap_or_default(); + +// let certs = if let Some(url) = steward { +// identity::steward(&url, crtreq).context("failed to attest to Steward")? +// } else { +// identity::selfsigned(&prvkey).context("failed to generate self-signed certificates")? +// } +// .into_iter() +// .map(rustls::Certificate) +// .collect::>(); + +// let mut config = wasmtime::Config::new(); +// // config.wasm_reference_types(true); // Enable reference types +// // config.wasm_function_references(true); // Enable function references +// // config.wasm_gc(true); // Enable garbage collection +// config.wasm_backtrace(true); +// config.native_unwind_info(true); // Enable threads +// config.debug_info(true); // Enable debug info +// config.memory_init_cow(false); +// config.async_support(false); + +// let engine = trace_span!("initialize Wasmtime engine") +// .in_scope(|| Engine::new(&config)) +// .context("failed to create execution engine")?; + +// let mut linker = trace_span!("setup linker").in_scope(|| Linker::new(&engine)); +// trace_span!("link WASI") +// .in_scope(|| add_to_linker_sync(&mut linker, |s| s)) +// .context("failed to setup linker and link WASI")?; + +// let mut builder = WasiCtxBuilder::new(); +// builder.inherit_stdio(); +// builder.inherit_stdin(); +// builder.inherit_stderr(); +// // builder.args(&["main.wasm", "/etc/resolv.conf", "/etc/resolv.conf"]); +// builder.preopened_dir("/home", ".", DirPerms::all(), FilePerms::all()).expect("failed to open current directory"); + +// //fs::File::open("/home/lind/enarx/test.txt").map_err(|err| format!("error opening input fuckup /home/lind/enarx/test.txt: {}", err)).unwrap(); + +// let mut wstore = trace_span!("initialize Wasmtime store") +// .in_scope(|| Store::new(&engine, builder.build_p1())); + +// let module = trace_span!("compile Wasm") +// .in_scope(|| Module::from_binary(&engine, &webasm)) +// .context("failed to compile Wasm module")?; +// trace_span!("link Wasm") +// .in_scope(|| linker.module(&mut wstore, "", &module)) +// .context("failed to link module")?; + +// let mut ctx = wstore.as_context_mut(); +// let ctx = ctx.data_mut(); + +// let func = trace_span!("get default function") +// .in_scope(|| linker.get_default(&mut wstore, "")) +// .context("failed to get default function")?; + +// let mut values = vec![Val::null_any_ref(); func.ty(&wstore).results().len()]; +// trace_span!("execute default function") +// .in_scope(|| func.call(wstore, Default::default(), &mut values)) +// .context("failed to execute default function")?; +// Ok(values) +// } +// } From b7c57564ee833525cd4c6ed5b65cf563d2e2a0a0 Mon Sep 17 00:00:00 2001 From: Yaxuan-w Date: Wed, 9 Jul 2025 11:25:34 -0400 Subject: [PATCH 3/7] Fix signal issue --- crates/exec-wasmtime/src/runtime/mod.rs | 89 ++++++++----------------- 1 file changed, 29 insertions(+), 60 deletions(-) diff --git a/crates/exec-wasmtime/src/runtime/mod.rs b/crates/exec-wasmtime/src/runtime/mod.rs index d3cfc0ca6..3a4fdc34b 100644 --- a/crates/exec-wasmtime/src/runtime/mod.rs +++ b/crates/exec-wasmtime/src/runtime/mod.rs @@ -240,28 +240,17 @@ impl Runtime { code = *res; } // exit the thread - // if rawposix::interface::lind_thread_exit( - // CAGE_START_ID as u64, - // THREAD_START_ID as u64, - // ) { - // // we clean the cage only if this is the last thread in the cage - // // exit the cage with the exit code - // lind_syscall_api(1, EXIT_SYSCALL as u32, 0, code as u64, 0, 0, 0, 0, 0); - - // // main cage exits - // lind_manager.decrement(); - // } - // we clean the cage only if this is the last thread in the cage - // exit the cage with the exit code - lind_syscall_api(1, EXIT_SYSCALL as u32, 0, code as u64, 0, 0, 0, 0, 0); - - // main cage exits - lind_manager.decrement(); - - // we wait until all other cage exits - lind_manager.wait(); - // after all cage exits, finalize the lind - rawposix::safeposix::dispatcher::lindrustfinalize(); + if rawposix::interface::lind_thread_exit( + CAGE_START_ID as u64, + THREAD_START_ID as u64, + ) { + // we clean the cage only if this is the last thread in the cage + // exit the cage with the exit code + lind_syscall_api(1, EXIT_SYSCALL as u32, 0, code as u64, 0, 0, 0, 0, 0); + + // main cage exits + lind_manager.decrement(); + } } Err(e) => { // Exit the process if Wasmtime understands the error; @@ -353,26 +342,6 @@ impl Runtime { // attach Lind-Multi-Process-Context to the host { - wstore.data_mut().lind_fork_ctx = Some(LindCtx::new( - module.clone(), - linker.clone(), - lind_manager.clone(), - // self.clone(), - webasm.clone(), - enarx_conf.clone(), - shared_next_cageid.clone(), - |host| host.lind_fork_ctx.as_mut().unwrap(), - |host| host.fork(), - |webasm, enarx_conf, path, args, pid, next_cageid, lind_manager, envs| { - Runtime::execute_with_lind( - webasm.clone(), - enarx_conf.clone(), - lind_manager.clone(), - pid as u64, - next_cageid.clone(), - ) - }, - )?); wstore.data_mut().lind_fork_ctx = Some(LindCtx::new_with_pid( module.clone(), linker.clone(), @@ -454,24 +423,24 @@ impl Runtime { store.as_context_mut().set_stack_top(stack_low as u64); // retrieve the epoch global - // let lind_epoch = instance - // .get_export(&mut *store, "epoch") - // .and_then(|export| export.into_global()) - // .expect("Failed to find epoch global export!"); - - // // retrieve the handler (underlying pointer) for the epoch global - // let pointer = lind_epoch.get_handler(&mut *store); - - // // initialize the signal for the main thread of the cage - // rawposix::interface::lind_signal_init( - // pid, - // pointer as *mut u64, - // THREAD_START_ID, - // true, /* this is the main thread */ - // ); - - // // see comments at signal_may_trigger for more details - // rawposix::interface::signal_may_trigger(pid); + let lind_epoch = instance + .get_export(&mut *store, "epoch") + .and_then(|export| export.into_global()) + .expect("Failed to find epoch global export!"); + + // retrieve the handler (underlying pointer) for the epoch global + let pointer = lind_epoch.get_handler(&mut *store); + + // initialize the signal for the main thread of the cage + rawposix::interface::lind_signal_init( + pid, + pointer as *mut u64, + THREAD_START_ID, + true, /* this is the main thread */ + ); + + // see comments at signal_may_trigger for more details + rawposix::interface::signal_may_trigger(pid); let result = match func { Some(func) => Runtime::invoke_func(store, func, &args), From 25f15dc90b1125a8d64cf02b811a7089aff75f70 Mon Sep 17 00:00:00 2001 From: Yaxuan-w Date: Wed, 9 Jul 2025 13:49:42 -0400 Subject: [PATCH 4/7] execv works --- crates/exec-wasmtime/src/runtime/mod.rs | 77 +------------------------ 1 file changed, 3 insertions(+), 74 deletions(-) diff --git a/crates/exec-wasmtime/src/runtime/mod.rs b/crates/exec-wasmtime/src/runtime/mod.rs index 3a4fdc34b..37d920e9b 100644 --- a/crates/exec-wasmtime/src/runtime/mod.rs +++ b/crates/exec-wasmtime/src/runtime/mod.rs @@ -272,6 +272,9 @@ impl Runtime { pid: u64, next_cageid: Arc, ) -> Result> { + + println!("Executing with Lind: pid: {}", pid); + let enarx_conf = config; let Config { steward, @@ -485,77 +488,3 @@ impl Runtime { } -// #[instrument] -// pub fn execute(package: Package) -> anyhow::Result> { -// let (prvkey, crtreq) = -// identity::generate().context("failed to generate a private key and CSR")?; - -// let Workload { webasm, config } = package.try_into()?; -// let Config { -// steward, -// args, -// files, -// env, -// } = config.unwrap_or_default(); - -// let certs = if let Some(url) = steward { -// identity::steward(&url, crtreq).context("failed to attest to Steward")? -// } else { -// identity::selfsigned(&prvkey).context("failed to generate self-signed certificates")? -// } -// .into_iter() -// .map(rustls::Certificate) -// .collect::>(); - -// let mut config = wasmtime::Config::new(); -// // config.wasm_reference_types(true); // Enable reference types -// // config.wasm_function_references(true); // Enable function references -// // config.wasm_gc(true); // Enable garbage collection -// config.wasm_backtrace(true); -// config.native_unwind_info(true); // Enable threads -// config.debug_info(true); // Enable debug info -// config.memory_init_cow(false); -// config.async_support(false); - -// let engine = trace_span!("initialize Wasmtime engine") -// .in_scope(|| Engine::new(&config)) -// .context("failed to create execution engine")?; - -// let mut linker = trace_span!("setup linker").in_scope(|| Linker::new(&engine)); -// trace_span!("link WASI") -// .in_scope(|| add_to_linker_sync(&mut linker, |s| s)) -// .context("failed to setup linker and link WASI")?; - -// let mut builder = WasiCtxBuilder::new(); -// builder.inherit_stdio(); -// builder.inherit_stdin(); -// builder.inherit_stderr(); -// // builder.args(&["main.wasm", "/etc/resolv.conf", "/etc/resolv.conf"]); -// builder.preopened_dir("/home", ".", DirPerms::all(), FilePerms::all()).expect("failed to open current directory"); - -// //fs::File::open("/home/lind/enarx/test.txt").map_err(|err| format!("error opening input fuckup /home/lind/enarx/test.txt: {}", err)).unwrap(); - -// let mut wstore = trace_span!("initialize Wasmtime store") -// .in_scope(|| Store::new(&engine, builder.build_p1())); - -// let module = trace_span!("compile Wasm") -// .in_scope(|| Module::from_binary(&engine, &webasm)) -// .context("failed to compile Wasm module")?; -// trace_span!("link Wasm") -// .in_scope(|| linker.module(&mut wstore, "", &module)) -// .context("failed to link module")?; - -// let mut ctx = wstore.as_context_mut(); -// let ctx = ctx.data_mut(); - -// let func = trace_span!("get default function") -// .in_scope(|| linker.get_default(&mut wstore, "")) -// .context("failed to get default function")?; - -// let mut values = vec![Val::null_any_ref(); func.ty(&wstore).results().len()]; -// trace_span!("execute default function") -// .in_scope(|| func.call(wstore, Default::default(), &mut values)) -// .context("failed to execute default function")?; -// Ok(values) -// } -// } From 369af74e101f48b1bb190b1f278deded16f8d87d Mon Sep 17 00:00:00 2001 From: Yaxuan-w Date: Wed, 9 Jul 2025 17:24:26 -0400 Subject: [PATCH 5/7] Works on passing arguments --- Enarx.toml | 3 ++ crates/exec-wasmtime/src/runtime/mod.rs | 53 +++++++++++++++++++++++-- 2 files changed, 52 insertions(+), 4 deletions(-) create mode 100644 Enarx.toml diff --git a/Enarx.toml b/Enarx.toml new file mode 100644 index 000000000..5834ff92e --- /dev/null +++ b/Enarx.toml @@ -0,0 +1,3 @@ +args = [ + "hello" +] diff --git a/crates/exec-wasmtime/src/runtime/mod.rs b/crates/exec-wasmtime/src/runtime/mod.rs index 37d920e9b..bdb84880a 100644 --- a/crates/exec-wasmtime/src/runtime/mod.rs +++ b/crates/exec-wasmtime/src/runtime/mod.rs @@ -166,7 +166,13 @@ impl Runtime { .in_scope(|| wasi_common::sync::add_to_linker(&mut linker, |s: &mut MyCtx| AsMut::::as_mut(s))) .context("failed to setup linker and link WASI")?; let mut builder = WasiCtxBuilder::new(); - builder.inherit_stdio(); + // In WASI, the argv semantics follow the POSIX convention: argv[0] is expected to be the program name, and argv[1..] + // are the actual arguments. However, in Enarx, we don’t have access to the original program name since the Wasm + // binary is typically loaded from a file descriptor rather than a path. As a result, we insert a placeholder + // value as argv[0] when constructing the argument list. + let mut full_args = vec!["main.wasm".to_string()]; + full_args.extend(args.clone()); + builder.inherit_stdio().args(&full_args); builder.inherit_stdin(); builder.inherit_stderr(); // builder.preopened_dir("/home", ".", DirPerms::all(), FilePerms::all()).expect("failed to open current directory"); @@ -201,9 +207,25 @@ impl Runtime { |host| host.lind_fork_ctx.as_mut().unwrap(), |host| host.fork(), |webasm, enarx_conf, path, args, pid, next_cageid, lind_manager, envs| { + // This closure is invoked during exec from `lind-multi-process::LindCtx::execve_call` in the lind-wasm. + // At that point, `args` has already been populated based on the inputs to `execv()`. + // In the current design of lind-wasm-enarx, the arguments field from Enarx.toml is only applied to the + // initial wasm module, and is not used for subsequent exec calls. Therefore, we explicitly override the + // `args` field inside `enarx_conf` here. + // Since the wasm binary is selected via the argument passed to `exec()`, we skip the first element of + // `args` (which represents the binary name). + // Additionally, when Enarx.toml is not provided, `enarx_conf` will be `None`, so we insert a default + // `enarx_config::Config` object as needed before updating its `args` field. + let mut new_enarx_conf = enarx_conf.clone(); + let conf = new_enarx_conf.get_or_insert_with(|| Config { + args: vec![], + ..Default::default() + }); + conf.args = args.get(1..).map_or(vec![], |s| s.to_vec()); + Runtime::execute_with_lind( webasm.clone(), - enarx_conf.clone(), + Some(conf.clone()), lind_manager.clone(), pid as u64, next_cageid.clone(), @@ -263,6 +285,7 @@ impl Runtime { result } + // This will only be called by exec_syscall() pub fn execute_with_lind( // Wasm module webasm: Vec, @@ -317,7 +340,13 @@ impl Runtime { .in_scope(|| wasi_common::sync::add_to_linker(&mut linker, |s: &mut MyCtx| AsMut::::as_mut(s))) .context("failed to setup linker and link WASI")?; let mut builder = WasiCtxBuilder::new(); - builder.inherit_stdio(); + // In WASI, the argv semantics follow the POSIX convention: argv[0] is expected to be the program name, and argv[1..] + // are the actual arguments. However, in Enarx, we don’t have access to the original program name since the Wasm + // binary is typically loaded from a file descriptor rather than a path. As a result, we insert a placeholder + // value as argv[0] when constructing the argument list. + let mut full_args = vec!["main.wasm".to_string()]; + full_args.extend(args.clone()); + builder.inherit_stdio().args(&full_args); builder.inherit_stdin(); builder.inherit_stderr(); // builder.preopened_dir("/home", ".", DirPerms::all(), FilePerms::all()).expect("failed to open current directory"); @@ -357,9 +386,25 @@ impl Runtime { |host| host.lind_fork_ctx.as_mut().unwrap(), |host| host.fork(), |webasm, enarx_conf, path, args, pid, next_cageid, lind_manager, envs| { + // This closure is invoked during exec from `lind-multi-process::LindCtx::execve_call` in the lind-wasm. + // At that point, `args` has already been populated based on the inputs to `execv()`. + // In the current design of lind-wasm-enarx, the arguments field from Enarx.toml is only applied to the + // initial wasm module, and is not used for subsequent exec calls. Therefore, we explicitly override the + // `args` field inside `enarx_conf` here. + // Since the wasm binary is selected via the argument passed to `exec()`, we skip the first element of + // `args` (which represents the binary name). + // Additionally, when Enarx.toml is not provided, `enarx_conf` will be `None`, so we insert a default + // `enarx_config::Config` object as needed before updating its `args` field. + let mut new_enarx_conf = enarx_conf.clone(); + let conf = new_enarx_conf.get_or_insert_with(|| Config { + args: vec![], + ..Default::default() + }); + conf.args = args.get(1..).map_or(vec![], |s| s.to_vec()); + Runtime::execute_with_lind( webasm.clone(), - enarx_conf.clone(), + Some(conf.clone()), lind_manager.clone(), pid as u64, next_cageid.clone(), From f2943dccaa0d70603297169f0e50044ded298eb7 Mon Sep 17 00:00:00 2001 From: Yaxuan-w Date: Wed, 9 Jul 2025 18:12:42 -0400 Subject: [PATCH 6/7] Cleanup and add comments --- crates/exec-wasmtime/src/runtime/mod.rs | 94 ++++++++++--------------- 1 file changed, 36 insertions(+), 58 deletions(-) diff --git a/crates/exec-wasmtime/src/runtime/mod.rs b/crates/exec-wasmtime/src/runtime/mod.rs index bdb84880a..9a28dc6ff 100644 --- a/crates/exec-wasmtime/src/runtime/mod.rs +++ b/crates/exec-wasmtime/src/runtime/mod.rs @@ -7,40 +7,27 @@ mod io; //mod net; use self::io::null::Null; -// use self::io::stdio_file; -//use self::net::{connect_file, listen_file}; use super::{Package, Workload}; -use wasmtime_lind_common::LindCommonCtx; -use wasmtime_lind_multi_process::{LindCtx, LindHost, CAGE_START_ID, THREAD_START_ID}; -use wasmtime_lind_utils::lind_syscall_numbers::EXIT_SYSCALL; -use wasmtime_lind_utils::LindCageManager; -use rawposix::safeposix::dispatcher::lind_syscall_api; -use std::sync::Arc; +use std::sync::{Arc, atomic::AtomicU64}; use cap_std::fs::Dir; -use wasmtime_wasi_threads::WasiThreadsCtx; -use std::sync::atomic::AtomicU64; -use anyhow::{anyhow, Result, bail}; -use wasmtime::{ - Func, InstantiateType, StoreLimits, ValType, -}; - -use anyhow::Context; +use anyhow::{anyhow, Result, bail, Context}; use enarx_config::{Config, File}; -// use wasi_common::snapshots::preview_1::types::Rights; -// use wasi_common::WasiFile; -use wasmtime::{AsContextMut, Engine, Linker, Module, Store, Val}; -// use wasmtime_wasi::{Stderr, Stdin, Stdout, StdoutStream, StdinStream, DirPerms, FilePerms}; -// use wasmtime_wasi::WasiCtxBuilder; +use wasmtime::{AsContextMut, Engine, Linker, Module, Store, Val, Func, InstantiateType, StoreLimits, ValType}; use wasi_common::sync::WasiCtxBuilder; -// use std::fs; -// use wasmtime_wasi::preview1::{add_to_linker_sync, WasiP1Ctx}; -// use wasmtime_wasi::{add_to_linker, WasiCtxBuilder}; -// use wiggle::tracing::{instrument, trace_span}; +use wasmtime_wasi_threads::WasiThreadsCtx; +use wasmtime_lind_common::LindCommonCtx; +use wasmtime_lind_multi_process::{LindCtx, LindHost, CAGE_START_ID, THREAD_START_ID}; +use wasmtime_lind_utils::{lind_syscall_numbers::EXIT_SYSCALL, LindCageManager}; +use rawposix::safeposix::dispatcher::lind_syscall_api; use wiggle::tracing::trace_span; -// Declare the context +/// The MyCtx host structure stores all relevant execution context objects +/// `preview1_ctx`: the WASI preview1 context (used by glibc and POSIX emulation); +/// `lind_common_ctx`: the context responsible for per-cage state management (e.g., signal handling, cage ID tracking); +/// `lind_fork_ctx`: the multi-process management structure, encapsulating fork/exec state; +/// `wasi_threads`: which manages WASI thread-related capabilities. #[derive(Default, Clone)] struct MyCtx { preview1_ctx: Option, @@ -49,6 +36,8 @@ struct MyCtx { lind_fork_ctx: Option>>, } +/// This implementation allows MyCtx to be used where a mutable reference to `wasi_common::WasiCtx` +/// is expected. impl AsMut for MyCtx { fn as_mut(&mut self) -> &mut wasi_common::WasiCtx { self.preview1_ctx @@ -58,6 +47,10 @@ impl AsMut for MyCtx { } impl MyCtx { + /// Performs a partial deep clone of the host context. It explicitly forks the WASI preview1 + /// context(`preview1_ctx`), the lind multi-process context (`lind_fork_ctx`), and the lind common + /// context (`lind_common_ctx`). Other parts of the context, such as `wasi_threads`, are shared + /// between forks since they are not required to be process-isolated. pub fn fork(&self) -> Self { // we want to do a real fork for wasi_preview1 context since glibc uses the environment variable // related interface here @@ -103,7 +96,11 @@ pub struct Runtime; impl Runtime { // Execute an Enarx [Package] - // #[instrument] + /// This function runs the first Wasm module in an Enarx Keep. It parses the Enarx package, + /// generates or attests an identity, sets up the Wasmtime engine, creates the initial store + /// and linker, and injects various contexts (WASI, lind-common, lind-multi-process). The + /// module is instantiated, and the main function is executed via load_main_module. This + /// function is the primary entry point for initial Wasm execution. pub fn execute(package: Package) -> anyhow::Result> { let (prvkey, crtreq) = identity::generate().context("failed to generate a private key and CSR")?; @@ -129,24 +126,13 @@ impl Runtime { .collect::>(); let mut config = wasmtime::Config::new(); - // config.wasm_reference_types(true); // Enable reference types - // config.wasm_function_references(true); // Enable function references - // config.wasm_gc(true); // Enable garbage collection - config.wasm_backtrace(true); - config.native_unwind_info(true); // Enable threads - config.debug_info(true); // Enable debug info - config.memory_init_cow(false); - // config.async_support(false); let engine = trace_span!("initialize Wasmtime engine") .in_scope(|| Engine::new(&config)) .context("failed to create execution engine")?; - // let wasi = builder.build(); let Host = MyCtx::default(); - // let mut wstore = trace_span!("initialize Wasmtime store") - // .in_scope(|| Store::new(&engine, builder.build_p1())); let mut wstore = trace_span!("initialize Wasmtime store") .in_scope(|| Store::new(&engine, Host)); @@ -175,7 +161,7 @@ impl Runtime { builder.inherit_stdio().args(&full_args); builder.inherit_stdin(); builder.inherit_stderr(); - // builder.preopened_dir("/home", ".", DirPerms::all(), FilePerms::all()).expect("failed to open current directory"); + let dir = Dir::open_ambient_dir("/home", cap_std::ambient_authority()).expect("failed to open /home"); builder.preopened_dir(dir, ".").expect("failed to open current directory"); wstore.data_mut().preview1_ctx = Some(builder.build()); @@ -200,7 +186,6 @@ impl Runtime { module.clone(), linker.clone(), lind_manager.clone(), - // self.clone(), webasm.clone(), enarx_conf.clone(), shared_next_cageid.clone(), @@ -285,7 +270,11 @@ impl Runtime { result } - // This will only be called by exec_syscall() + /// This function is called when a new Wasm module is executed via an exec() syscall inside + /// a Wasm process. It mirrors much of the behavior of execute, but instead of reading + /// configuration from Enarx.toml, it uses an updated or synthetic config passed in at runtime. + /// This config has its args explicitly overridden. A new MyCtx is created, associated with + /// a new PID, and the module is launched in its own cage. pub fn execute_with_lind( // Wasm module webasm: Vec, @@ -295,9 +284,6 @@ impl Runtime { pid: u64, next_cageid: Arc, ) -> Result> { - - println!("Executing with Lind: pid: {}", pid); - let enarx_conf = config; let Config { steward, @@ -307,24 +293,13 @@ impl Runtime { } = enarx_conf.clone().unwrap_or_default(); let mut config = wasmtime::Config::new(); - // config.wasm_reference_types(true); // Enable reference types - // config.wasm_function_references(true); // Enable function references - // config.wasm_gc(true); // Enable garbage collection - config.wasm_backtrace(true); - config.native_unwind_info(true); // Enable threads - config.debug_info(true); // Enable debug info - config.memory_init_cow(false); - // config.async_support(false); let engine = trace_span!("initialize Wasmtime engine") .in_scope(|| Engine::new(&config)) .context("failed to create execution engine")?; - // let wasi = builder.build(); let Host = MyCtx::default(); - // let mut wstore = trace_span!("initialize Wasmtime store") - // .in_scope(|| Store::new(&engine, builder.build_p1())); let mut wstore = trace_span!("initialize Wasmtime store") .in_scope(|| Store::new(&engine, Host)); @@ -349,7 +324,7 @@ impl Runtime { builder.inherit_stdio().args(&full_args); builder.inherit_stdin(); builder.inherit_stderr(); - // builder.preopened_dir("/home", ".", DirPerms::all(), FilePerms::all()).expect("failed to open current directory"); + let dir = Dir::open_ambient_dir("/home", cap_std::ambient_authority()).expect("failed to open /home"); builder.preopened_dir(dir, ".").expect("failed to open current directory"); wstore.data_mut().preview1_ctx = Some(builder.build()); @@ -378,7 +353,6 @@ impl Runtime { module.clone(), linker.clone(), lind_manager.clone(), - // self.clone(), webasm.clone(), enarx_conf.clone(), pid as i32, @@ -436,6 +410,9 @@ impl Runtime { result } + /// This function takes a compiled module, instantiates it with the current store and linker, + /// and executes its entry point. This is the point where the Wasm "process" actually starts + /// executing. fn load_main_module( store: &mut Store, linker: &mut Linker, @@ -497,6 +474,8 @@ impl Runtime { result } + /// This function takes a Wasm function (Func) and a list of string arguments, parses the + /// arguments into Wasm values based on expected types (ValType), and invokes the function fn invoke_func(store: &mut Store, func: Func, args: &[String]) -> Result> { let ty = func.ty(&store); if ty.params().len() > 0 { @@ -505,7 +484,6 @@ impl Runtime { is experimental and may break in the future" ); } - // let mut args = self.module_and_args.iter().skip(1); let mut args = args.iter(); let mut values = Vec::new(); for ty in ty.params() { From 06849b527eab622784308dd3e3ec761a65cd0fe5 Mon Sep 17 00:00:00 2001 From: Yaxuan-w Date: Thu, 10 Jul 2025 11:07:37 -0400 Subject: [PATCH 7/7] Rename host ctx struct and remove magic constant --- crates/exec-wasmtime/src/runtime/mod.rs | 55 ++++++++++++++----------- 1 file changed, 30 insertions(+), 25 deletions(-) diff --git a/crates/exec-wasmtime/src/runtime/mod.rs b/crates/exec-wasmtime/src/runtime/mod.rs index 9a28dc6ff..bd19375c5 100644 --- a/crates/exec-wasmtime/src/runtime/mod.rs +++ b/crates/exec-wasmtime/src/runtime/mod.rs @@ -23,22 +23,27 @@ use wasmtime_lind_utils::{lind_syscall_numbers::EXIT_SYSCALL, LindCageManager}; use rawposix::safeposix::dispatcher::lind_syscall_api; use wiggle::tracing::trace_span; -/// The MyCtx host structure stores all relevant execution context objects +/// The base directory to preopen during the Wasm module linking stage, +/// used to grant ambient directory access (via capability-based I/O) +/// before instantiating the module. +static HOME_DIR_PATH: &str = "/home"; + +/// The HostCtx host structure stores all relevant execution context objects /// `preview1_ctx`: the WASI preview1 context (used by glibc and POSIX emulation); /// `lind_common_ctx`: the context responsible for per-cage state management (e.g., signal handling, cage ID tracking); /// `lind_fork_ctx`: the multi-process management structure, encapsulating fork/exec state; /// `wasi_threads`: which manages WASI thread-related capabilities. #[derive(Default, Clone)] -struct MyCtx { +struct HostCtx { preview1_ctx: Option, - wasi_threads: Option>>, + wasi_threads: Option>>, lind_common_ctx: Option, - lind_fork_ctx: Option>>, + lind_fork_ctx: Option>>, } -/// This implementation allows MyCtx to be used where a mutable reference to `wasi_common::WasiCtx` +/// This implementation allows HostCtx to be used where a mutable reference to `wasi_common::WasiCtx` /// is expected. -impl AsMut for MyCtx { +impl AsMut for HostCtx { fn as_mut(&mut self) -> &mut wasi_common::WasiCtx { self.preview1_ctx .as_mut() @@ -46,7 +51,7 @@ impl AsMut for MyCtx { } } -impl MyCtx { +impl HostCtx { /// Performs a partial deep clone of the host context. It explicitly forks the WASI preview1 /// context(`preview1_ctx`), the lind multi-process context (`lind_fork_ctx`), and the lind common /// context (`lind_common_ctx`). Other parts of the context, such as `wasi_threads`, are shared @@ -84,8 +89,8 @@ impl MyCtx { } } -impl LindHost> for MyCtx { - fn get_ctx(&self) -> LindCtx> { +impl LindHost> for HostCtx { + fn get_ctx(&self) -> LindCtx> { self.lind_fork_ctx.clone().unwrap() } } @@ -131,10 +136,10 @@ impl Runtime { .in_scope(|| Engine::new(&config)) .context("failed to create execution engine")?; - let Host = MyCtx::default(); + let host = HostCtx::default(); let mut wstore = trace_span!("initialize Wasmtime store") - .in_scope(|| Store::new(&engine, Host)); + .in_scope(|| Store::new(&engine, host)); let module = trace_span!("compile Wasm") .in_scope(|| Module::from_binary(&engine, &webasm)) @@ -149,7 +154,7 @@ impl Runtime { let mut linker = trace_span!("setup linker").in_scope(|| Linker::new(&engine)); // Setup WASI-p1 trace_span!("link WASI") - .in_scope(|| wasi_common::sync::add_to_linker(&mut linker, |s: &mut MyCtx| AsMut::::as_mut(s))) + .in_scope(|| wasi_common::sync::add_to_linker(&mut linker, |s: &mut HostCtx| AsMut::::as_mut(s))) .context("failed to setup linker and link WASI")?; let mut builder = WasiCtxBuilder::new(); // In WASI, the argv semantics follow the POSIX convention: argv[0] is expected to be the program name, and argv[1..] @@ -162,19 +167,19 @@ impl Runtime { builder.inherit_stdin(); builder.inherit_stderr(); - let dir = Dir::open_ambient_dir("/home", cap_std::ambient_authority()).expect("failed to open /home"); + let dir = Dir::open_ambient_dir(HOME_DIR_PATH, cap_std::ambient_authority()).expect(&format!("failed to open {}", HOME_DIR_PATH)); builder.preopened_dir(dir, ".").expect("failed to open current directory"); wstore.data_mut().preview1_ctx = Some(builder.build()); // Setup WASI-thread trace_span!("link WASI-thread") - .in_scope(|| wasmtime_wasi_threads::add_to_linker(&mut linker, &wstore, &module, |s: &mut MyCtx| s.wasi_threads.as_ref().unwrap())) + .in_scope(|| wasmtime_wasi_threads::add_to_linker(&mut linker, &wstore, &module, |s: &mut HostCtx| s.wasi_threads.as_ref().unwrap())) .context("failed to setup linker and link WASI")?; // attach Lind-Common-Context to the host let shared_next_cageid = Arc::new(AtomicU64::new(1)); { - wasmtime_lind_common::add_to_linker::>(&mut linker, |host| { + wasmtime_lind_common::add_to_linker::>(&mut linker, |host| { host.lind_common_ctx.as_ref().unwrap() })?; wstore.data_mut().lind_common_ctx = Some(LindCommonCtx::new(shared_next_cageid.clone())?); @@ -273,7 +278,7 @@ impl Runtime { /// This function is called when a new Wasm module is executed via an exec() syscall inside /// a Wasm process. It mirrors much of the behavior of execute, but instead of reading /// configuration from Enarx.toml, it uses an updated or synthetic config passed in at runtime. - /// This config has its args explicitly overridden. A new MyCtx is created, associated with + /// This config has its args explicitly overridden. A new HostCtx is created, associated with /// a new PID, and the module is launched in its own cage. pub fn execute_with_lind( // Wasm module @@ -298,10 +303,10 @@ impl Runtime { .in_scope(|| Engine::new(&config)) .context("failed to create execution engine")?; - let Host = MyCtx::default(); + let host = HostCtx::default(); let mut wstore = trace_span!("initialize Wasmtime store") - .in_scope(|| Store::new(&engine, Host)); + .in_scope(|| Store::new(&engine, host)); let module = trace_span!("compile Wasm") .in_scope(|| Module::from_binary(&engine, &webasm)) @@ -312,7 +317,7 @@ impl Runtime { let mut linker = trace_span!("setup linker").in_scope(|| Linker::new(&engine)); // Setup WASI-p1 trace_span!("link WASI") - .in_scope(|| wasi_common::sync::add_to_linker(&mut linker, |s: &mut MyCtx| AsMut::::as_mut(s))) + .in_scope(|| wasi_common::sync::add_to_linker(&mut linker, |s: &mut HostCtx| AsMut::::as_mut(s))) .context("failed to setup linker and link WASI")?; let mut builder = WasiCtxBuilder::new(); // In WASI, the argv semantics follow the POSIX convention: argv[0] is expected to be the program name, and argv[1..] @@ -325,19 +330,19 @@ impl Runtime { builder.inherit_stdin(); builder.inherit_stderr(); - let dir = Dir::open_ambient_dir("/home", cap_std::ambient_authority()).expect("failed to open /home"); + let dir = Dir::open_ambient_dir(HOME_DIR_PATH, cap_std::ambient_authority()).expect(&format!("failed to open {}", HOME_DIR_PATH)); builder.preopened_dir(dir, ".").expect("failed to open current directory"); wstore.data_mut().preview1_ctx = Some(builder.build()); // Setup WASI-thread trace_span!("link WASI-thread") - .in_scope(|| wasmtime_wasi_threads::add_to_linker(&mut linker, &wstore, &module, |s: &mut MyCtx| s.wasi_threads.as_ref().unwrap())) + .in_scope(|| wasmtime_wasi_threads::add_to_linker(&mut linker, &wstore, &module, |s: &mut HostCtx| s.wasi_threads.as_ref().unwrap())) .context("failed to setup linker and link WASI")?; // attach Lind-Common-Context to the host let shared_next_cageid = Arc::new(AtomicU64::new(1)); { - wasmtime_lind_common::add_to_linker::>(&mut linker, |host| { + wasmtime_lind_common::add_to_linker::>(&mut linker, |host| { host.lind_common_ctx.as_ref().unwrap() })?; // Create a new lind ctx with the next cage ID since we are going to fork @@ -414,8 +419,8 @@ impl Runtime { /// and executes its entry point. This is the point where the Wasm "process" actually starts /// executing. fn load_main_module( - store: &mut Store, - linker: &mut Linker, + store: &mut Store, + linker: &mut Linker, module: &Module, pid: u64, args: &[String], @@ -476,7 +481,7 @@ impl Runtime { /// This function takes a Wasm function (Func) and a list of string arguments, parses the /// arguments into Wasm values based on expected types (ValType), and invokes the function - fn invoke_func(store: &mut Store, func: Func, args: &[String]) -> Result> { + fn invoke_func(store: &mut Store, func: Func, args: &[String]) -> Result> { let ty = func.ty(&store); if ty.params().len() > 0 { eprintln!(