From c78cb79a176885428d36bea196ca9940cc327012 Mon Sep 17 00:00:00 2001 From: Victor Adossi Date: Sun, 15 Oct 2023 09:44:15 +0900 Subject: [PATCH] feat: use refactored walrus API After the work done upstreaming operations used in `src/walrus_ops.rs` to walrus, the code for WASI-Virt can be updated to use the new APIs and reduce custom code. This commit updates the WASI-Virt codebase to use the upstreamed functions and adds some light refactors to the more mechanical pieces of code for stubbing/denying/stripping. see: https://github.com/bytecodealliance/WASI-Virt/issues/20 Signed-off-by: Victor Adossi --- Cargo.lock | 8 +- Cargo.toml | 13 +- src/data.rs | 13 +- src/virt_deny.rs | 771 -------------------------------- src/virt_deny/clocks.rs | 71 +++ src/virt_deny/exit.rs | 19 + src/virt_deny/http.rs | 233 ++++++++++ src/virt_deny/mod.rs | 39 ++ src/virt_deny/random.rs | 57 +++ src/virt_deny/sockets.rs | 357 +++++++++++++++ src/virt_env.rs | 46 +- src/virt_io.rs | 943 +++++++++++++++++++++------------------ src/walrus_ops.rs | 111 +---- tests/virt.rs | 2 +- 14 files changed, 1347 insertions(+), 1336 deletions(-) delete mode 100644 src/virt_deny.rs create mode 100644 src/virt_deny/clocks.rs create mode 100644 src/virt_deny/exit.rs create mode 100644 src/virt_deny/http.rs create mode 100644 src/virt_deny/mod.rs create mode 100644 src/virt_deny/random.rs create mode 100644 src/virt_deny/sockets.rs diff --git a/Cargo.lock b/Cargo.lock index e483701..40433e3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1900,8 +1900,7 @@ dependencies = [ [[package]] name = "walrus" version = "0.20.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc27d837c587f863d99515dc8cae7cef1098bd1d99fa29373e3660c12766265e" +source = "git+https://github.com/vados-cosmonic/walrus?branch=refactor/improve-ergonomics-of-fn-replace#f74b1851e7a3fe47e7a02b5c36ad4320a7b6878f" dependencies = [ "anyhow", "gimli 0.26.2", @@ -1916,13 +1915,12 @@ dependencies = [ [[package]] name = "walrus-macro" version = "0.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a6e5bd22c71e77d60140b0bd5be56155a37e5bd14e24f5f87298040d0cc40d7" +source = "git+https://github.com/vados-cosmonic/walrus?branch=refactor/improve-ergonomics-of-fn-replace#f74b1851e7a3fe47e7a02b5c36ad4320a7b6878f" dependencies = [ "heck 0.3.3", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.37", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index ccca0f2..72aa098 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,7 +18,7 @@ members = [ "tests/components/do-everything", "tests/components/file-read", "tests/components/get-env", - "tests/components/stdio" + "tests/components/stdio", ] [profile.release] @@ -33,7 +33,8 @@ anyhow = "1" clap = { version = "4", features = ["derive"] } serde = { version = "1", features = ["derive"] } toml = "0.7" -walrus = "0.20.1" +# TODO: use published version of walrus w/ improved ergonomics +walrus = { git = "https://github.com/vados-cosmonic/walrus", branch = "refactor/improve-ergonomics-of-fn-replace" } wasm-compose = "0.4.2" wasm-metadata = "0.10.5" wasm-opt = "0.114.1" @@ -45,12 +46,14 @@ anyhow = "1" [dev-dependencies] anyhow = "1" cap-std = "1.0.12" -heck = { version = "0.4" } +heck = { version = "0.4" } tokio = { version = "1.30.0", features = ["macros"] } -wasmtime = { git = "https://github.com/bytecodealliance/wasmtime", features = ["component-model"] } +wasmtime = { git = "https://github.com/bytecodealliance/wasmtime", features = [ + "component-model", +] } wasmtime-wasi = { git = "https://github.com/bytecodealliance/wasmtime" } wasmparser = "0.113.1" [workspace.dependencies] anyhow = "1" -wit-bindgen = "0.12.0" \ No newline at end of file +wit-bindgen = "0.12.0" diff --git a/src/data.rs b/src/data.rs index ee54588..1267237 100644 --- a/src/data.rs +++ b/src/data.rs @@ -1,6 +1,3 @@ -use crate::walrus_ops::{ - bump_stack_global, get_exported_func, get_memory_id, remove_exported_func, -}; use anyhow::{bail, Result}; use std::collections::HashMap; use walrus::{ @@ -8,6 +5,8 @@ use walrus::{ FunctionKind, InitExpr, Module, ValType, }; +use crate::walrus_ops::bump_stack_global; + /// Data section /// Because data is stack-allocated we create a corresponding byte vector as large /// as the stack, zero fill it then populate it backwards from the @@ -115,7 +114,7 @@ impl Data { } pub fn finish(mut self, module: &mut Module) -> Result<()> { // stack embedding - let memory = get_memory_id(module)?; + let memory = module.get_memory_id()?; let rem = (self.stack_start - self.stack_ptr) % 8; if rem != 0 { self.stack_ptr -= 8 - rem; @@ -132,7 +131,7 @@ impl Data { // passive segment embedding // we create one function for each passive segment, due to if self.passive_segments.len() > 0 { - let alloc_fid = get_exported_func(module, "cabi_realloc")?; + let alloc_fid = module.exports.get_func_by_name("cabi_realloc")?; let offset_local = module.locals.add(ValType::I32); let len_local = module.locals.add(ValType::I32); @@ -206,13 +205,13 @@ impl Data { .call_indirect(passive_fn_alloc_type, passive_tid); // update the existing passive_alloc function export with the new function body - let passive_alloc_fid = get_exported_func(module, "passive_alloc")?; + let passive_alloc_fid = module.exports.get_func_by_name("passive_alloc")?; let passive_alloc_func = module.funcs.get_mut(passive_alloc_fid); passive_alloc_func.kind = FunctionKind::Local(builder.local_func(vec![passive_idx, offset_local, len_local])); } - remove_exported_func(module, "passive_alloc")?; + module.exports.delete_func_by_name("passive_alloc")?; Ok(()) } diff --git a/src/virt_deny.rs b/src/virt_deny.rs deleted file mode 100644 index 3056715..0000000 --- a/src/virt_deny.rs +++ /dev/null @@ -1,771 +0,0 @@ -use anyhow::Result; -use walrus::{Module, ValType}; - -use crate::{ - virt_io::{stub_clocks_virt, stub_http_virt, stub_sockets_virt}, - walrus_ops::add_stub_exported_func, -}; - -// set exports to deny clock access -pub(crate) fn deny_clocks_virt(module: &mut Module) -> Result<()> { - stub_clocks_virt(module)?; - add_stub_exported_func( - module, - "wasi:clocks/monotonic-clock#now", - vec![], - vec![ValType::I64], - )?; - add_stub_exported_func( - module, - "wasi:clocks/monotonic-clock#resolution", - vec![], - vec![ValType::I64], - )?; - add_stub_exported_func( - module, - "wasi:clocks/monotonic-clock#subscribe", - vec![ValType::I64, ValType::I32], - vec![ValType::I32], - )?; - - add_stub_exported_func( - module, - "wasi:clocks/wall-clock#now", - vec![], - vec![ValType::I32], - )?; - add_stub_exported_func( - module, - "wasi:clocks/wall-clock#resolution", - vec![], - vec![ValType::I32], - )?; - add_stub_exported_func( - module, - "wasi:clocks/wall-clock#subscribe", - vec![ValType::I64, ValType::I32], - vec![ValType::I32], - )?; - - add_stub_exported_func( - module, - "wasi:clocks/timezone#display", - vec![ValType::I32, ValType::I64, ValType::I32], - vec![ValType::I32], - )?; - add_stub_exported_func( - module, - "cabi_post_wasi:clocks/timezone#display", - vec![ValType::I32], - vec![], - )?; - add_stub_exported_func( - module, - "wasi:clocks/timezone#utc-offset", - vec![ValType::I32, ValType::I64, ValType::I32], - vec![ValType::I32], - )?; - add_stub_exported_func( - module, - "wasi:clocks/timezone#drop-timezone", - vec![ValType::I32], - vec![], - )?; - - Ok(()) -} - -pub(crate) fn deny_http_virt(module: &mut Module) -> Result<()> { - stub_http_virt(module)?; - add_stub_exported_func( - module, - "wasi:http/incoming-handler#handle", - vec![ValType::I32, ValType::I32], - vec![], - )?; - add_stub_exported_func( - module, - "wasi:http/outgoing-handler#handle", - vec![ - ValType::I32, - ValType::I32, - ValType::I32, - ValType::I32, - ValType::I32, - ValType::I32, - ValType::I32, - ValType::I32, - ], - vec![ValType::I32], - )?; - add_stub_exported_func( - module, - "wasi:http/types#drop-fields", - vec![ValType::I32], - vec![], - )?; - add_stub_exported_func( - module, - "wasi:http/types#new-fields", - vec![ValType::I32, ValType::I32], - vec![ValType::I32], - )?; - add_stub_exported_func( - module, - "wasi:http/types#fields-get", - vec![ValType::I32, ValType::I32, ValType::I32], - vec![ValType::I32], - )?; - add_stub_exported_func( - module, - "wasi:http/types#fields-set", - vec![ - ValType::I32, - ValType::I32, - ValType::I32, - ValType::I32, - ValType::I32, - ], - vec![], - )?; - add_stub_exported_func( - module, - "wasi:http/types#fields-delete", - vec![ValType::I32, ValType::I32, ValType::I32], - vec![], - )?; - add_stub_exported_func( - module, - "wasi:http/types#fields-append", - vec![ - ValType::I32, - ValType::I32, - ValType::I32, - ValType::I32, - ValType::I32, - ], - vec![], - )?; - add_stub_exported_func( - module, - "wasi:http/types#fields-entries", - vec![ValType::I32], - vec![ValType::I32], - )?; - add_stub_exported_func( - module, - "wasi:http/types#fields-clone", - vec![ValType::I32], - vec![ValType::I32], - )?; - add_stub_exported_func( - module, - "wasi:http/types#finish-incoming-stream", - vec![ValType::I32], - vec![ValType::I32], - )?; - add_stub_exported_func( - module, - "wasi:http/types#finish-outgoing-stream", - vec![ValType::I32, ValType::I32, ValType::I32], - vec![], - )?; - add_stub_exported_func( - module, - "wasi:http/types#drop-incoming-request", - vec![ValType::I32], - vec![], - )?; - add_stub_exported_func( - module, - "wasi:http/types#drop-outgoing-request", - vec![ValType::I32], - vec![], - )?; - add_stub_exported_func( - module, - "wasi:http/types#incoming-request-method", - vec![ValType::I32], - vec![ValType::I32], - )?; - add_stub_exported_func( - module, - "wasi:http/types#incoming-request-path-with-query", - vec![ValType::I32], - vec![ValType::I32], - )?; - add_stub_exported_func( - module, - "wasi:http/types#incoming-request-scheme", - vec![ValType::I32], - vec![ValType::I32], - )?; - add_stub_exported_func( - module, - "wasi:http/types#incoming-request-authority", - vec![ValType::I32], - vec![ValType::I32], - )?; - add_stub_exported_func( - module, - "wasi:http/types#incoming-request-headers", - vec![ValType::I32], - vec![ValType::I32], - )?; - add_stub_exported_func( - module, - "wasi:http/types#incoming-request-consume", - vec![ValType::I32], - vec![ValType::I32], - )?; - add_stub_exported_func( - module, - "wasi:http/types#new-outgoing-request", - vec![ - ValType::I32, - ValType::I32, - ValType::I32, - ValType::I32, - ValType::I32, - ValType::I32, - ValType::I32, - ValType::I32, - ValType::I32, - ValType::I32, - ValType::I32, - ValType::I32, - ValType::I32, - ValType::I32, - ], - vec![ValType::I32], - )?; - add_stub_exported_func( - module, - "wasi:http/types#outgoing-request-write", - vec![ValType::I32], - vec![ValType::I32], - )?; - add_stub_exported_func( - module, - "wasi:http/types#drop-response-outparam", - vec![ValType::I32], - vec![], - )?; - add_stub_exported_func( - module, - "wasi:http/types#set-response-outparam", - vec![ - ValType::I32, - ValType::I32, - ValType::I32, - ValType::I32, - ValType::I32, - ], - vec![ValType::I32], - )?; - add_stub_exported_func( - module, - "wasi:http/types#drop-incoming-response", - vec![ValType::I32], - vec![], - )?; - add_stub_exported_func( - module, - "wasi:http/types#drop-outgoing-response", - vec![ValType::I32], - vec![], - )?; - add_stub_exported_func( - module, - "wasi:http/types#incoming-response-status", - vec![ValType::I32], - vec![ValType::I32], - )?; - add_stub_exported_func( - module, - "wasi:http/types#incoming-response-headers", - vec![ValType::I32], - vec![ValType::I32], - )?; - add_stub_exported_func( - module, - "wasi:http/types#incoming-response-consume", - vec![ValType::I32], - vec![ValType::I32], - )?; - add_stub_exported_func( - module, - "wasi:http/types#new-outgoing-response", - vec![ValType::I32, ValType::I32], - vec![ValType::I32], - )?; - add_stub_exported_func( - module, - "wasi:http/types#outgoing-response-write", - vec![ValType::I32], - vec![ValType::I32], - )?; - add_stub_exported_func( - module, - "wasi:http/types#drop-future-incoming-response", - vec![ValType::I32], - vec![], - )?; - add_stub_exported_func( - module, - "wasi:http/types#future-incoming-response-get", - vec![ValType::I32], - vec![ValType::I32], - )?; - add_stub_exported_func( - module, - "wasi:http/types#listen-to-future-incoming-response", - vec![ValType::I32], - vec![ValType::I32], - )?; - Ok(()) -} - -pub(crate) fn deny_random_virt(module: &mut Module) -> Result<()> { - add_stub_exported_func( - module, - "wasi:random/random#get-random-bytes", - vec![ValType::I64], - vec![ValType::I32], - )?; - add_stub_exported_func( - module, - "cabi_post_wasi:random/random#get-random-bytes", - vec![ValType::I32], - vec![], - )?; - add_stub_exported_func( - module, - "wasi:random/random#get-random-u64", - vec![], - vec![ValType::I64], - )?; - add_stub_exported_func( - module, - "wasi:random/insecure#get-insecure-random-bytes", - vec![ValType::I64], - vec![ValType::I32], - )?; - add_stub_exported_func( - module, - "cabi_post_wasi:random/insecure#get-insecure-random-bytes", - vec![ValType::I32], - vec![], - )?; - add_stub_exported_func( - module, - "wasi:random/insecure#get-insecure-random-u64", - vec![], - vec![ValType::I64], - )?; - add_stub_exported_func( - module, - "wasi:random/insecure-seed#insecure-seed", - vec![], - vec![ValType::I32], - )?; - Ok(()) -} - -pub(crate) fn deny_exit_virt(module: &mut Module) -> Result<()> { - add_stub_exported_func(module, "wasi:cli/exit#exit", vec![ValType::I32], vec![])?; - Ok(()) -} - -pub(crate) fn deny_sockets_virt(module: &mut Module) -> Result<()> { - stub_sockets_virt(module)?; - add_stub_exported_func( - module, - "wasi:sockets/network#drop-network", - vec![ValType::I32], - vec![], - )?; - add_stub_exported_func( - module, - "wasi:sockets/instance-network#instance-network", - vec![], - vec![ValType::I32], - )?; - add_stub_exported_func( - module, - "wasi:sockets/ip-name-lookup#resolve-addresses", - vec![ - ValType::I32, - ValType::I32, - ValType::I32, - ValType::I32, - ValType::I32, - ValType::I32, - ], - vec![ValType::I32], - )?; - add_stub_exported_func( - module, - "wasi:sockets/ip-name-lookup#resolve-next-address", - vec![ValType::I32], - vec![ValType::I32], - )?; - add_stub_exported_func( - module, - "wasi:sockets/ip-name-lookup#drop-resolve-address-stream", - vec![ValType::I32], - vec![], - )?; - add_stub_exported_func( - module, - "wasi:sockets/ip-name-lookup#subscribe", - vec![ValType::I32], - vec![ValType::I32], - )?; - add_stub_exported_func( - module, - "wasi:sockets/tcp-create-socket#create-tcp-socket", - vec![ValType::I32], - vec![ValType::I32], - )?; - add_stub_exported_func( - module, - "wasi:sockets/tcp#start-bind", - vec![ - ValType::I32, - ValType::I32, - ValType::I32, - ValType::I32, - ValType::I32, - ValType::I32, - ValType::I32, - ValType::I32, - ValType::I32, - ValType::I32, - ValType::I32, - ValType::I32, - ValType::I32, - ValType::I32, - ], - vec![ValType::I32], - )?; - add_stub_exported_func( - module, - "wasi:sockets/tcp#finish-bind", - vec![ValType::I32], - vec![ValType::I32], - )?; - add_stub_exported_func( - module, - "wasi:sockets/tcp#start-connect", - vec![ - ValType::I32, - ValType::I32, - ValType::I32, - ValType::I32, - ValType::I32, - ValType::I32, - ValType::I32, - ValType::I32, - ValType::I32, - ValType::I32, - ValType::I32, - ValType::I32, - ValType::I32, - ValType::I32, - ], - vec![ValType::I32], - )?; - add_stub_exported_func( - module, - "wasi:sockets/tcp#finish-connect", - vec![ValType::I32], - vec![ValType::I32], - )?; - add_stub_exported_func( - module, - "wasi:sockets/tcp#start-listen", - vec![ValType::I32], - vec![ValType::I32], - )?; - add_stub_exported_func( - module, - "wasi:sockets/tcp#finish-listen", - vec![ValType::I32], - vec![ValType::I32], - )?; - add_stub_exported_func( - module, - "wasi:sockets/tcp#accept", - vec![ValType::I32], - vec![ValType::I32], - )?; - add_stub_exported_func( - module, - "wasi:sockets/tcp#local-address", - vec![ValType::I32], - vec![ValType::I32], - )?; - add_stub_exported_func( - module, - "wasi:sockets/tcp#remote-address", - vec![ValType::I32], - vec![ValType::I32], - )?; - add_stub_exported_func( - module, - "wasi:sockets/tcp#address-family", - vec![ValType::I32], - vec![ValType::I32], - )?; - add_stub_exported_func( - module, - "wasi:sockets/tcp#ipv6-only", - vec![ValType::I32], - vec![ValType::I32], - )?; - add_stub_exported_func( - module, - "wasi:sockets/tcp#set-ipv6-only", - vec![ValType::I32, ValType::I32], - vec![ValType::I32], - )?; - add_stub_exported_func( - module, - "wasi:sockets/tcp#set-listen-backlog-size", - vec![ValType::I32, ValType::I64], - vec![ValType::I32], - )?; - add_stub_exported_func( - module, - "wasi:sockets/tcp#keep-alive", - vec![ValType::I32], - vec![ValType::I32], - )?; - add_stub_exported_func( - module, - "wasi:sockets/tcp#set-keep-alive", - vec![ValType::I32, ValType::I32], - vec![ValType::I32], - )?; - add_stub_exported_func( - module, - "wasi:sockets/tcp#no-delay", - vec![ValType::I32], - vec![ValType::I32], - )?; - add_stub_exported_func( - module, - "wasi:sockets/tcp#set-no-delay", - vec![ValType::I32, ValType::I32], - vec![ValType::I32], - )?; - add_stub_exported_func( - module, - "wasi:sockets/tcp#unicast-hop-limit", - vec![ValType::I32], - vec![ValType::I32], - )?; - add_stub_exported_func( - module, - "wasi:sockets/tcp#set-unicast-hop-limit", - vec![ValType::I32, ValType::I32], - vec![ValType::I32], - )?; - add_stub_exported_func( - module, - "wasi:sockets/tcp#receive-buffer-size", - vec![ValType::I32], - vec![ValType::I32], - )?; - add_stub_exported_func( - module, - "wasi:sockets/tcp#set-receive-buffer-size", - vec![ValType::I32, ValType::I64], - vec![ValType::I32], - )?; - add_stub_exported_func( - module, - "wasi:sockets/tcp#send-buffer-size", - vec![ValType::I32], - vec![ValType::I32], - )?; - add_stub_exported_func( - module, - "wasi:sockets/tcp#set-send-buffer-size", - vec![ValType::I32, ValType::I64], - vec![ValType::I32], - )?; - add_stub_exported_func( - module, - "wasi:sockets/tcp#subscribe", - vec![ValType::I32], - vec![ValType::I32], - )?; - add_stub_exported_func( - module, - "wasi:sockets/tcp#shutdown", - vec![ValType::I32, ValType::I32], - vec![ValType::I32], - )?; - add_stub_exported_func( - module, - "wasi:sockets/tcp#drop-tcp-socket", - vec![ValType::I32], - vec![], - )?; - - add_stub_exported_func( - module, - "wasi:sockets/udp-create-socket#create-udp-socket", - vec![ValType::I32], - vec![ValType::I32], - )?; - - add_stub_exported_func( - module, - "wasi:sockets/udp#start-bind", - vec![ - ValType::I32, - ValType::I32, - ValType::I32, - ValType::I32, - ValType::I32, - ValType::I32, - ValType::I32, - ValType::I32, - ValType::I32, - ValType::I32, - ValType::I32, - ValType::I32, - ValType::I32, - ValType::I32, - ], - vec![ValType::I32], - )?; - add_stub_exported_func( - module, - "wasi:sockets/udp#finish-bind", - vec![ValType::I32], - vec![ValType::I32], - )?; - add_stub_exported_func( - module, - "wasi:sockets/udp#start-connect", - vec![ - ValType::I32, - ValType::I32, - ValType::I32, - ValType::I32, - ValType::I32, - ValType::I32, - ValType::I32, - ValType::I32, - ValType::I32, - ValType::I32, - ValType::I32, - ValType::I32, - ValType::I32, - ValType::I32, - ], - vec![ValType::I32], - )?; - add_stub_exported_func( - module, - "wasi:sockets/udp#finish-connect", - vec![ValType::I32], - vec![ValType::I32], - )?; - add_stub_exported_func( - module, - "wasi:sockets/udp#receive", - vec![ValType::I32, ValType::I64], - vec![ValType::I32], - )?; - add_stub_exported_func( - module, - "wasi:sockets/udp#send", - vec![ValType::I32, ValType::I32, ValType::I32], - vec![ValType::I32], - )?; - add_stub_exported_func( - module, - "wasi:sockets/udp#local-address", - vec![ValType::I32], - vec![ValType::I32], - )?; - add_stub_exported_func( - module, - "wasi:sockets/udp#remote-address", - vec![ValType::I32], - vec![ValType::I32], - )?; - add_stub_exported_func( - module, - "wasi:sockets/udp#address-family", - vec![ValType::I32], - vec![ValType::I32], - )?; - add_stub_exported_func( - module, - "wasi:sockets/udp#ipv6-only", - vec![ValType::I32], - vec![ValType::I32], - )?; - add_stub_exported_func( - module, - "wasi:sockets/udp#set-ipv6-only", - vec![ValType::I32, ValType::I32], - vec![ValType::I32], - )?; - add_stub_exported_func( - module, - "wasi:sockets/udp#unicast-hop-limit", - vec![ValType::I32], - vec![ValType::I32], - )?; - add_stub_exported_func( - module, - "wasi:sockets/udp#set-unicast-hop-limit", - vec![ValType::I32, ValType::I32], - vec![ValType::I32], - )?; - add_stub_exported_func( - module, - "wasi:sockets/udp#receive-buffer-size", - vec![ValType::I32], - vec![ValType::I32], - )?; - add_stub_exported_func( - module, - "wasi:sockets/udp#set-receive-buffer-size", - vec![ValType::I32, ValType::I64], - vec![ValType::I32], - )?; - add_stub_exported_func( - module, - "wasi:sockets/udp#send-buffer-size", - vec![ValType::I32], - vec![ValType::I32], - )?; - add_stub_exported_func( - module, - "wasi:sockets/udp#set-send-buffer-size", - vec![ValType::I32, ValType::I64], - vec![ValType::I32], - )?; - add_stub_exported_func( - module, - "wasi:sockets/udp#subscribe", - vec![ValType::I32], - vec![ValType::I32], - )?; - add_stub_exported_func( - module, - "wasi:sockets/udp#drop-udp-socket", - vec![ValType::I32], - vec![], - )?; - - Ok(()) -} diff --git a/src/virt_deny/clocks.rs b/src/virt_deny/clocks.rs new file mode 100644 index 0000000..c22440f --- /dev/null +++ b/src/virt_deny/clocks.rs @@ -0,0 +1,71 @@ +use std::sync::OnceLock; + +use anyhow::Result; +use walrus::{FuncParams, FuncResults, Module, ValType}; + +use crate::virt_io::stub_clocks_virt; + +use super::replace_or_insert_stub_for_exports; + +/// Functions that represent the environment functionality provided by WASI clocks +static WASI_CLOCK_FNS: OnceLock> = OnceLock::new(); + +/// Retrieve or initialize the static list of functions related to clocks in WASI +fn get_wasi_clock_fns() -> &'static Vec<(&'static str, FuncParams, FuncResults)> { + WASI_CLOCK_FNS.get_or_init(|| { + Vec::from([ + ( + "wasi:clocks/monotonic-clock#now", + vec![], + vec![ValType::I64], + ), + ( + "wasi:clocks/monotonic-clock#resolution", + vec![], + vec![ValType::I64], + ), + ( + "wasi:clocks/monotonic-clock#subscribe", + vec![ValType::I64, ValType::I32], + vec![ValType::I32], + ), + ("wasi:clocks/wall-clock#now", vec![], vec![ValType::I32]), + ( + "wasi:clocks/wall-clock#resolution", + vec![], + vec![ValType::I32], + ), + ( + "wasi:clocks/wall-clock#subscribe", + vec![ValType::I64, ValType::I32], + vec![ValType::I32], + ), + ( + "wasi:clocks/timezone#display", + vec![ValType::I32, ValType::I64, ValType::I32], + vec![ValType::I32], + ), + ( + "cabi_post_wasi:clocks/timezone#display", + vec![ValType::I32], + vec![], + ), + ( + "wasi:clocks/timezone#utc-offset", + vec![ValType::I32, ValType::I64, ValType::I32], + vec![ValType::I32], + ), + ( + "wasi:clocks/timezone#drop-timezone", + vec![ValType::I32], + vec![], + ), + ]) + }) +} + +/// Replace exports related to clocks in WASI to deny access +pub(crate) fn deny_clocks_virt(module: &mut Module) -> Result<()> { + stub_clocks_virt(module)?; + replace_or_insert_stub_for_exports(module, get_wasi_clock_fns()) +} diff --git a/src/virt_deny/exit.rs b/src/virt_deny/exit.rs new file mode 100644 index 0000000..7d0b546 --- /dev/null +++ b/src/virt_deny/exit.rs @@ -0,0 +1,19 @@ +use std::sync::OnceLock; + +use anyhow::Result; +use walrus::{FuncParams, FuncResults, Module, ValType}; + +use super::replace_or_insert_stub_for_exports; + +/// Functions that represent the environment functionality provided by WASI exits +static WASI_EXIT_FNS: OnceLock> = OnceLock::new(); + +/// Retrieve or initialize the static list of functions related to exiting in WASI +fn get_wasi_exit_fns() -> &'static Vec<(&'static str, FuncParams, FuncResults)> { + WASI_EXIT_FNS.get_or_init(|| Vec::from([("wasi:cli/exit#exit", vec![ValType::I32], vec![])])) +} + +/// Replace exports related to exiting in WASI to deny access +pub(crate) fn deny_exit_virt(module: &mut Module) -> Result<()> { + replace_or_insert_stub_for_exports(module, get_wasi_exit_fns()) +} diff --git a/src/virt_deny/http.rs b/src/virt_deny/http.rs new file mode 100644 index 0000000..7d12361 --- /dev/null +++ b/src/virt_deny/http.rs @@ -0,0 +1,233 @@ +use std::sync::OnceLock; + +use anyhow::Result; +use walrus::{FuncParams, FuncResults, Module, ValType}; + +use crate::virt_io::stub_http_virt; + +use super::replace_or_insert_stub_for_exports; + +/// Functions that represent the HTTP functionality provided by WASI https +pub(crate) static WASI_HTTP_FNS: OnceLock> = OnceLock::new(); + +/// Retrieve or initialize the static list of functions related to HTTP in WASI +fn get_wasi_http_fns() -> &'static Vec<(&'static str, FuncParams, FuncResults)> { + WASI_HTTP_FNS.get_or_init(|| { + Vec::from([ + ( + "wasi:http/incoming-handler#handle", + vec![ValType::I32, ValType::I32], + vec![], + ), + ( + "wasi:http/outgoing-handler#handle", + vec![ + ValType::I32, + ValType::I32, + ValType::I32, + ValType::I32, + ValType::I32, + ValType::I32, + ValType::I32, + ValType::I32, + ], + vec![ValType::I32], + ), + ("wasi:http/types#drop-fields", vec![ValType::I32], vec![]), + ( + "wasi:http/types#new-fields", + vec![ValType::I32, ValType::I32], + vec![ValType::I32], + ), + ( + "wasi:http/types#fields-get", + vec![ValType::I32, ValType::I32, ValType::I32], + vec![ValType::I32], + ), + ( + "wasi:http/types#fields-set", + vec![ + ValType::I32, + ValType::I32, + ValType::I32, + ValType::I32, + ValType::I32, + ], + vec![], + ), + ( + "wasi:http/types#fields-delete", + vec![ValType::I32, ValType::I32, ValType::I32], + vec![], + ), + ( + "wasi:http/types#fields-append", + vec![ + ValType::I32, + ValType::I32, + ValType::I32, + ValType::I32, + ValType::I32, + ], + vec![], + ), + ( + "wasi:http/types#fields-entries", + vec![ValType::I32], + vec![ValType::I32], + ), + ( + "wasi:http/types#fields-clone", + vec![ValType::I32], + vec![ValType::I32], + ), + ( + "wasi:http/types#finish-incoming-stream", + vec![ValType::I32], + vec![ValType::I32], + ), + ( + "wasi:http/types#finish-outgoing-stream", + vec![ValType::I32, ValType::I32, ValType::I32], + vec![], + ), + ( + "wasi:http/types#drop-incoming-request", + vec![ValType::I32], + vec![], + ), + ( + "wasi:http/types#drop-outgoing-request", + vec![ValType::I32], + vec![], + ), + ( + "wasi:http/types#incoming-request-method", + vec![ValType::I32], + vec![ValType::I32], + ), + ( + "wasi:http/types#incoming-request-path-with-query", + vec![ValType::I32], + vec![ValType::I32], + ), + ( + "wasi:http/types#incoming-request-scheme", + vec![ValType::I32], + vec![ValType::I32], + ), + ( + "wasi:http/types#incoming-request-authority", + vec![ValType::I32], + vec![ValType::I32], + ), + ( + "wasi:http/types#incoming-request-headers", + vec![ValType::I32], + vec![ValType::I32], + ), + ( + "wasi:http/types#incoming-request-consume", + vec![ValType::I32], + vec![ValType::I32], + ), + ( + "wasi:http/types#new-outgoing-request", + vec![ + ValType::I32, + ValType::I32, + ValType::I32, + ValType::I32, + ValType::I32, + ValType::I32, + ValType::I32, + ValType::I32, + ValType::I32, + ValType::I32, + ValType::I32, + ValType::I32, + ValType::I32, + ValType::I32, + ], + vec![ValType::I32], + ), + ( + "wasi:http/types#outgoing-request-write", + vec![ValType::I32], + vec![ValType::I32], + ), + ( + "wasi:http/types#drop-response-outparam", + vec![ValType::I32], + vec![], + ), + ( + "wasi:http/types#set-response-outparam", + vec![ + ValType::I32, + ValType::I32, + ValType::I32, + ValType::I32, + ValType::I32, + ], + vec![ValType::I32], + ), + ( + "wasi:http/types#drop-incoming-response", + vec![ValType::I32], + vec![], + ), + ( + "wasi:http/types#drop-outgoing-response", + vec![ValType::I32], + vec![], + ), + ( + "wasi:http/types#incoming-response-status", + vec![ValType::I32], + vec![ValType::I32], + ), + ( + "wasi:http/types#incoming-response-headers", + vec![ValType::I32], + vec![ValType::I32], + ), + ( + "wasi:http/types#incoming-response-consume", + vec![ValType::I32], + vec![ValType::I32], + ), + ( + "wasi:http/types#new-outgoing-response", + vec![ValType::I32, ValType::I32], + vec![ValType::I32], + ), + ( + "wasi:http/types#outgoing-response-write", + vec![ValType::I32], + vec![ValType::I32], + ), + ( + "wasi:http/types#drop-future-incoming-response", + vec![ValType::I32], + vec![], + ), + ( + "wasi:http/types#future-incoming-response-get", + vec![ValType::I32], + vec![ValType::I32], + ), + ( + "wasi:http/types#listen-to-future-incoming-response", + vec![ValType::I32], + vec![ValType::I32], + ), + ]) + }) +} + +/// Replace exports related to HTTP in WASI to deny access +pub(crate) fn deny_http_virt(module: &mut Module) -> Result<()> { + stub_http_virt(module)?; + replace_or_insert_stub_for_exports(module, get_wasi_http_fns()) +} diff --git a/src/virt_deny/mod.rs b/src/virt_deny/mod.rs new file mode 100644 index 0000000..5242432 --- /dev/null +++ b/src/virt_deny/mod.rs @@ -0,0 +1,39 @@ +use anyhow::Result; +use walrus::{ExportItem, FuncParams, FuncResults, FunctionBuilder, Module}; + +mod clocks; +mod exit; +mod http; +mod random; +mod sockets; +pub(crate) use clocks::deny_clocks_virt; +pub(crate) use exit::deny_exit_virt; +pub(crate) use http::deny_http_virt; +pub(crate) use random::deny_random_virt; +pub(crate) use sockets::deny_sockets_virt; + +/// Helper function for replacing or inserting exports with stub functions +fn replace_or_insert_stub_for_exports<'a>( + module: &mut Module, + exports: impl IntoIterator, +) -> Result<()> { + for (export_name, params, results) in exports { + // If the export exists, replace it directly + if let Ok(fid) = module.exports.get_func_by_name(&export_name) { + module.replace_exported_func(fid, |(body, _)| { + body.unreachable(); + })?; + continue; + } + + // Create and use a new stub function for the export + let mut builder = FunctionBuilder::new(&mut module.types, ¶ms, &results); + let mut body = builder.func_body(); + body.unreachable(); + module.exports.add( + &export_name, + ExportItem::Function(module.funcs.add_local(builder.local_func(vec![]))), + ); + } + Ok(()) +} diff --git a/src/virt_deny/random.rs b/src/virt_deny/random.rs new file mode 100644 index 0000000..760996b --- /dev/null +++ b/src/virt_deny/random.rs @@ -0,0 +1,57 @@ +use std::sync::OnceLock; + +use anyhow::Result; +use walrus::{FuncParams, FuncResults, Module, ValType}; + +use super::replace_or_insert_stub_for_exports; + +/// Functions that represent the environment functionality provided by WASI randoms +static WASI_RANDOM_FNS: OnceLock> = OnceLock::new(); + +/// Retrieve or initialize the static list of functions related to randomness in WASI +fn get_wasi_random_fns() -> &'static Vec<(&'static str, FuncParams, FuncResults)> { + WASI_RANDOM_FNS.get_or_init(|| { + Vec::from([ + ( + "wasi:random/random#get-random-bytes", + vec![ValType::I64], + vec![ValType::I32], + ), + ( + "cabi_post_wasi:random/random#get-random-bytes", + vec![ValType::I32], + vec![], + ), + ( + "wasi:random/random#get-random-u64", + vec![], + vec![ValType::I64], + ), + ( + "wasi:random/insecure#get-insecure-random-bytes", + vec![ValType::I64], + vec![ValType::I32], + ), + ( + "cabi_post_wasi:random/insecure#get-insecure-random-bytes", + vec![ValType::I32], + vec![], + ), + ( + "wasi:random/insecure#get-insecure-random-u64", + vec![], + vec![ValType::I64], + ), + ( + "wasi:random/insecure-seed#insecure-seed", + vec![], + vec![ValType::I32], + ), + ]) + }) +} + +/// Replace exports related to randomness in WASI to deny access +pub(crate) fn deny_random_virt(module: &mut Module) -> Result<()> { + replace_or_insert_stub_for_exports(module, get_wasi_random_fns()) +} diff --git a/src/virt_deny/sockets.rs b/src/virt_deny/sockets.rs new file mode 100644 index 0000000..b19ca3b --- /dev/null +++ b/src/virt_deny/sockets.rs @@ -0,0 +1,357 @@ +use std::sync::OnceLock; + +use anyhow::Result; +use walrus::{FuncParams, FuncResults, Module, ValType}; + +use crate::virt_io::stub_sockets_virt; + +use super::replace_or_insert_stub_for_exports; + +/// Functions that represent the environment functionality provided by WASI sockets +static WASI_SOCKETS_FNS: OnceLock> = OnceLock::new(); + +/// Retrieve or initialize the static list of functions related to sockets in WASI +pub fn get_wasi_sockets_fns() -> &'static Vec<(&'static str, FuncParams, FuncResults)> { + WASI_SOCKETS_FNS.get_or_init(|| { + Vec::from([ + ( + "wasi:sockets/network#drop-network", + vec![ValType::I32], + vec![], + ), + ( + "wasi:sockets/instance-network#instance-network", + vec![], + vec![ValType::I32], + ), + ( + "wasi:sockets/ip-name-lookup#resolve-addresses", + vec![ + ValType::I32, + ValType::I32, + ValType::I32, + ValType::I32, + ValType::I32, + ValType::I32, + ], + vec![ValType::I32], + ), + ( + "wasi:sockets/ip-name-lookup#resolve-next-address", + vec![ValType::I32], + vec![ValType::I32], + ), + ( + "wasi:sockets/ip-name-lookup#drop-resolve-address-stream", + vec![ValType::I32], + vec![], + ), + ( + "wasi:sockets/ip-name-lookup#subscribe", + vec![ValType::I32], + vec![ValType::I32], + ), + ( + "wasi:sockets/tcp-create-socket#create-tcp-socket", + vec![ValType::I32], + vec![ValType::I32], + ), + ( + "wasi:sockets/tcp#start-bind", + vec![ + ValType::I32, + ValType::I32, + ValType::I32, + ValType::I32, + ValType::I32, + ValType::I32, + ValType::I32, + ValType::I32, + ValType::I32, + ValType::I32, + ValType::I32, + ValType::I32, + ValType::I32, + ValType::I32, + ], + vec![ValType::I32], + ), + ( + "wasi:sockets/tcp#finish-bind", + vec![ValType::I32], + vec![ValType::I32], + ), + ( + "wasi:sockets/tcp#start-connect", + vec![ + ValType::I32, + ValType::I32, + ValType::I32, + ValType::I32, + ValType::I32, + ValType::I32, + ValType::I32, + ValType::I32, + ValType::I32, + ValType::I32, + ValType::I32, + ValType::I32, + ValType::I32, + ValType::I32, + ], + vec![ValType::I32], + ), + ( + "wasi:sockets/tcp#finish-connect", + vec![ValType::I32], + vec![ValType::I32], + ), + ( + "wasi:sockets/tcp#start-listen", + vec![ValType::I32], + vec![ValType::I32], + ), + ( + "wasi:sockets/tcp#finish-listen", + vec![ValType::I32], + vec![ValType::I32], + ), + ( + "wasi:sockets/tcp#accept", + vec![ValType::I32], + vec![ValType::I32], + ), + ( + "wasi:sockets/tcp#local-address", + vec![ValType::I32], + vec![ValType::I32], + ), + ( + "wasi:sockets/tcp#remote-address", + vec![ValType::I32], + vec![ValType::I32], + ), + ( + "wasi:sockets/tcp#address-family", + vec![ValType::I32], + vec![ValType::I32], + ), + ( + "wasi:sockets/tcp#ipv6-only", + vec![ValType::I32], + vec![ValType::I32], + ), + ( + "wasi:sockets/tcp#set-ipv6-only", + vec![ValType::I32, ValType::I32], + vec![ValType::I32], + ), + ( + "wasi:sockets/tcp#set-listen-backlog-size", + vec![ValType::I32, ValType::I64], + vec![ValType::I32], + ), + ( + "wasi:sockets/tcp#keep-alive", + vec![ValType::I32], + vec![ValType::I32], + ), + ( + "wasi:sockets/tcp#set-keep-alive", + vec![ValType::I32, ValType::I32], + vec![ValType::I32], + ), + ( + "wasi:sockets/tcp#no-delay", + vec![ValType::I32], + vec![ValType::I32], + ), + ( + "wasi:sockets/tcp#set-no-delay", + vec![ValType::I32, ValType::I32], + vec![ValType::I32], + ), + ( + "wasi:sockets/tcp#unicast-hop-limit", + vec![ValType::I32], + vec![ValType::I32], + ), + ( + "wasi:sockets/tcp#set-unicast-hop-limit", + vec![ValType::I32, ValType::I32], + vec![ValType::I32], + ), + ( + "wasi:sockets/tcp#receive-buffer-size", + vec![ValType::I32], + vec![ValType::I32], + ), + ( + "wasi:sockets/tcp#set-receive-buffer-size", + vec![ValType::I32, ValType::I64], + vec![ValType::I32], + ), + ( + "wasi:sockets/tcp#send-buffer-size", + vec![ValType::I32], + vec![ValType::I32], + ), + ( + "wasi:sockets/tcp#set-send-buffer-size", + vec![ValType::I32, ValType::I64], + vec![ValType::I32], + ), + ( + "wasi:sockets/tcp#subscribe", + vec![ValType::I32], + vec![ValType::I32], + ), + ( + "wasi:sockets/tcp#shutdown", + vec![ValType::I32, ValType::I32], + vec![ValType::I32], + ), + ( + "wasi:sockets/tcp#drop-tcp-socket", + vec![ValType::I32], + vec![], + ), + ( + "wasi:sockets/udp-create-socket#create-udp-socket", + vec![ValType::I32], + vec![ValType::I32], + ), + ( + "wasi:sockets/udp#start-bind", + vec![ + ValType::I32, + ValType::I32, + ValType::I32, + ValType::I32, + ValType::I32, + ValType::I32, + ValType::I32, + ValType::I32, + ValType::I32, + ValType::I32, + ValType::I32, + ValType::I32, + ValType::I32, + ValType::I32, + ], + vec![ValType::I32], + ), + ( + "wasi:sockets/udp#finish-bind", + vec![ValType::I32], + vec![ValType::I32], + ), + ( + "wasi:sockets/udp#start-connect", + vec![ + ValType::I32, + ValType::I32, + ValType::I32, + ValType::I32, + ValType::I32, + ValType::I32, + ValType::I32, + ValType::I32, + ValType::I32, + ValType::I32, + ValType::I32, + ValType::I32, + ValType::I32, + ValType::I32, + ], + vec![ValType::I32], + ), + ( + "wasi:sockets/udp#finish-connect", + vec![ValType::I32], + vec![ValType::I32], + ), + ( + "wasi:sockets/udp#receive", + vec![ValType::I32, ValType::I64], + vec![ValType::I32], + ), + ( + "wasi:sockets/udp#send", + vec![ValType::I32, ValType::I32, ValType::I32], + vec![ValType::I32], + ), + ( + "wasi:sockets/udp#local-address", + vec![ValType::I32], + vec![ValType::I32], + ), + ( + "wasi:sockets/udp#remote-address", + vec![ValType::I32], + vec![ValType::I32], + ), + ( + "wasi:sockets/udp#address-family", + vec![ValType::I32], + vec![ValType::I32], + ), + ( + "wasi:sockets/udp#ipv6-only", + vec![ValType::I32], + vec![ValType::I32], + ), + ( + "wasi:sockets/udp#set-ipv6-only", + vec![ValType::I32, ValType::I32], + vec![ValType::I32], + ), + ( + "wasi:sockets/udp#unicast-hop-limit", + vec![ValType::I32], + vec![ValType::I32], + ), + ( + "wasi:sockets/udp#set-unicast-hop-limit", + vec![ValType::I32, ValType::I32], + vec![ValType::I32], + ), + ( + "wasi:sockets/udp#receive-buffer-size", + vec![ValType::I32], + vec![ValType::I32], + ), + ( + "wasi:sockets/udp#set-receive-buffer-size", + vec![ValType::I32, ValType::I64], + vec![ValType::I32], + ), + ( + "wasi:sockets/udp#send-buffer-size", + vec![ValType::I32], + vec![ValType::I32], + ), + ( + "wasi:sockets/udp#set-send-buffer-size", + vec![ValType::I32, ValType::I64], + vec![ValType::I32], + ), + ( + "wasi:sockets/udp#subscribe", + vec![ValType::I32], + vec![ValType::I32], + ), + ( + "wasi:sockets/udp#drop-udp-socket", + vec![ValType::I32], + vec![], + ), + ]) + }) +} + +/// Replace exports related to sockets in WASI to deny access +pub(crate) fn deny_sockets_virt(module: &mut Module) -> Result<()> { + stub_sockets_virt(module)?; + replace_or_insert_stub_for_exports(module, get_wasi_sockets_fns()) +} diff --git a/src/virt_env.rs b/src/virt_env.rs index 28f494c..1b2c721 100644 --- a/src/virt_env.rs +++ b/src/virt_env.rs @@ -1,13 +1,11 @@ -use crate::walrus_ops::{ - bump_stack_global, get_active_data_segment, get_memory_id, remove_exported_func, - stub_imported_func, -}; use anyhow::{bail, Context, Result}; use serde::Deserialize; use walrus::{ ir::Value, ActiveData, ActiveDataLocation, DataKind, ExportItem, GlobalKind, InitExpr, Module, }; +use crate::walrus_ops::{bump_stack_global, get_active_data_segment}; + #[derive(Deserialize, Debug, Clone, Default)] #[serde(deny_unknown_fields)] pub struct VirtEnv { @@ -95,7 +93,7 @@ pub(crate) fn create_env_virt<'a>(module: &'a mut Module, env: &VirtEnv) -> Resu // we do arguments as well because virt assumes reactors for now... } - let memory = get_memory_id(module)?; + let memory = module.get_memory_id()?; // prepare the field data list vector for writing // strings must be sorted as binary searches are used against this data @@ -213,17 +211,43 @@ pub(crate) fn create_env_virt<'a>(module: &'a mut Module, env: &VirtEnv) -> Resu Ok(()) } +/// Functions that represent the environment functionality provided by WASI CLI +const WASI_ENV_FNS: [&str; 3] = ["get-arguments", "get-environment", "initial-cwd"]; + +/// Stub imported functions that implement the WASI CLI environment functionality +/// +/// This function throws an error if any imported functions do not exist pub(crate) fn stub_env_virt(module: &mut Module) -> Result<()> { - stub_imported_func(module, "wasi:cli/environment", "get-arguments", true)?; - stub_imported_func(module, "wasi:cli/environment", "get-environment", true)?; - stub_imported_func(module, "wasi:cli/environment", "initial-cwd", true)?; + for fn_name in WASI_ENV_FNS { + module.replace_imported_func( + module + .imports + .get_func_by_name("wasi:cli/environment", fn_name)?, + |(body, _)| { + body.unreachable(); + }, + )?; + } + Ok(()) } +/// Strip exported functions that implement the WASI CLI environment functionality +/// +/// This function *does not* throw an error if an export does not exist. pub(crate) fn strip_env_virt(module: &mut Module) -> Result<()> { stub_env_virt(module)?; - remove_exported_func(module, "wasi:cli/environment#get-arguments")?; - remove_exported_func(module, "wasi:cli/environment#get-environment")?; - remove_exported_func(module, "wasi:cli/environment#initial-cwd")?; + + for fn_name in WASI_ENV_FNS { + if let Ok(fid) = module + .exports + .get_func_by_name(format!("wasi:cli/environment#{fn_name}")) + { + module.replace_exported_func(fid, |(body, _)| { + body.unreachable(); + })?; + }; + } + Ok(()) } diff --git a/src/virt_io.rs b/src/virt_io.rs index 0293488..e395853 100644 --- a/src/virt_io.rs +++ b/src/virt_io.rs @@ -6,10 +6,9 @@ use clap::ValueEnum; use serde::Deserialize; use walrus::{ir::Value, ExportItem, GlobalKind, InitExpr, Module}; -use crate::walrus_ops::remove_exported_func; use crate::{ data::{Data, WasmEncode}, - walrus_ops::{get_active_data_segment, get_stack_global, stub_imported_func}, + walrus_ops::{get_active_data_segment, get_stack_global}, }; pub type VirtualFiles = BTreeMap; @@ -562,486 +561,576 @@ pub(crate) fn create_io_virt<'a>( Ok(virtual_files) } +/// Imports exposed by WASI for Filesystem functionality which are allowed to be missing +const WASI_FS_IMPORTS: [(&str, &str); 28] = [ + ("wasi:filesystem/types", "write-via-stream"), + ("wasi:filesystem/types", "append-via-stream"), + ("wasi:filesystem/types", "advise"), + ("wasi:filesystem/types", "sync-data"), + ("wasi:filesystem/types", "get-flags"), + ("wasi:filesystem/types", "set-size"), + ("wasi:filesystem/types", "set-times"), + ("wasi:filesystem/types", "write"), + ("wasi:filesystem/types", "read-directory"), + ("wasi:filesystem/types", "sync"), + ("wasi:filesystem/types", "create-directory-at"), + ("wasi:filesystem/types", "set-times-at"), + ("wasi:filesystem/types", "link-at"), + ("wasi:filesystem/types", "readlink-at"), + ("wasi:filesystem/types", "remove-directory-at"), + ("wasi:filesystem/types", "rename-at"), + ("wasi:filesystem/types", "symlink-at"), + ("wasi:filesystem/types", "access-at"), + ("wasi:filesystem/types", "unlink-file-at"), + ("wasi:filesystem/types", "change-file-permissions-at"), + ("wasi:filesystem/types", "change-directory-permissions-at"), + ("wasi:filesystem/types", "lock-shared"), + ("wasi:filesystem/types", "lock-exclusive"), + ("wasi:filesystem/types", "try-lock-shared"), + ("wasi:filesystem/types", "try-lock-exclusive"), + ("wasi:filesystem/types", "unlock"), + ("wasi:filesystem/types", "metadata-hash"), + ("wasi:filesystem/types", "metadata-hash-at"), +]; + +/// Filesystem exposed by WASI for HTTP functionality, which *must* +/// exist, and be replaced by stubs/controlled by WASI-Virt +const WASI_FS_IMPORTS_REQUIRED: [(&str, &str); 11] = [ + ("wasi:filesystem/preopens", "get-directories"), + ("wasi:filesystem/types", "read-via-stream"), + ("wasi:filesystem/types", "get-type"), + ("wasi:filesystem/types", "read"), + ("wasi:filesystem/types", "stat"), + ("wasi:filesystem/types", "stat-at"), + ("wasi:filesystem/types", "open-at"), + ("wasi:filesystem/types", "drop-descriptor"), + ("wasi:filesystem/types", "read-directory-entry"), + ("wasi:filesystem/types", "drop-directory-entry-stream"), + ("wasi:filesystem/types", "is-same-object"), +]; + +/// Replace imported WASI functions that implement filesystem access with no-ops // Stubs must be _comprehensive_ in order to act as full deny over entire subsystem // when stubbing functions that are not part of the virtual adapter exports, we therefore // have to create this functions fresh. // Ideally, we should generate these stubs automatically from WASI definitions. pub(crate) fn stub_fs_virt(module: &mut Module, uses_fs: bool) -> Result<()> { - stub_imported_func( - module, - "wasi:filesystem/preopens", - "get-directories", - uses_fs, - )?; - stub_imported_func(module, "wasi:filesystem/types", "read-via-stream", uses_fs)?; - stub_imported_func(module, "wasi:filesystem/types", "write-via-stream", false)?; - stub_imported_func(module, "wasi:filesystem/types", "append-via-stream", false)?; - stub_imported_func(module, "wasi:filesystem/types", "advise", false)?; - stub_imported_func(module, "wasi:filesystem/types", "sync-data", false)?; - stub_imported_func(module, "wasi:filesystem/types", "get-flags", false)?; - stub_imported_func(module, "wasi:filesystem/types", "get-type", uses_fs)?; - stub_imported_func(module, "wasi:filesystem/types", "set-size", false)?; - stub_imported_func(module, "wasi:filesystem/types", "set-times", false)?; - stub_imported_func(module, "wasi:filesystem/types", "read", uses_fs)?; - stub_imported_func(module, "wasi:filesystem/types", "write", false)?; - stub_imported_func(module, "wasi:filesystem/types", "read-directory", false)?; - stub_imported_func(module, "wasi:filesystem/types", "sync", false)?; - stub_imported_func( - module, - "wasi:filesystem/types", - "create-directory-at", - false, - )?; - stub_imported_func(module, "wasi:filesystem/types", "stat", uses_fs)?; - stub_imported_func(module, "wasi:filesystem/types", "stat-at", uses_fs)?; - stub_imported_func(module, "wasi:filesystem/types", "set-times-at", false)?; - stub_imported_func(module, "wasi:filesystem/types", "link-at", false)?; - stub_imported_func(module, "wasi:filesystem/types", "open-at", uses_fs)?; - stub_imported_func(module, "wasi:filesystem/types", "readlink-at", false)?; - stub_imported_func( - module, - "wasi:filesystem/types", - "remove-directory-at", - false, - )?; - stub_imported_func(module, "wasi:filesystem/types", "rename-at", false)?; - stub_imported_func(module, "wasi:filesystem/types", "symlink-at", false)?; - stub_imported_func(module, "wasi:filesystem/types", "access-at", false)?; - stub_imported_func(module, "wasi:filesystem/types", "unlink-file-at", false)?; - stub_imported_func( - module, - "wasi:filesystem/types", - "change-file-permissions-at", - false, - )?; - stub_imported_func( - module, - "wasi:filesystem/types", - "change-directory-permissions-at", - false, - )?; - stub_imported_func(module, "wasi:filesystem/types", "lock-shared", false)?; - stub_imported_func(module, "wasi:filesystem/types", "lock-exclusive", false)?; - stub_imported_func(module, "wasi:filesystem/types", "try-lock-shared", false)?; - stub_imported_func(module, "wasi:filesystem/types", "try-lock-exclusive", false)?; - stub_imported_func(module, "wasi:filesystem/types", "unlock", false)?; - stub_imported_func(module, "wasi:filesystem/types", "drop-descriptor", uses_fs)?; - stub_imported_func( - module, - "wasi:filesystem/types", - "read-directory-entry", - uses_fs, - )?; - stub_imported_func( - module, - "wasi:filesystem/types", - "drop-directory-entry-stream", - uses_fs, - )?; - stub_imported_func(module, "wasi:filesystem/types", "is-same-object", uses_fs)?; - stub_imported_func(module, "wasi:filesystem/types", "metadata-hash", false)?; - stub_imported_func(module, "wasi:filesystem/types", "metadata-hash-at", false)?; + // Replace the filesystem functions that are allowed to be missing + for (module_name, func_name) in WASI_FS_IMPORTS { + if let Ok(fid) = module.imports.get_func_by_name(module_name, func_name) { + module + .replace_imported_func(fid, |(body, _)| { + body.unreachable(); + }) + .with_context(|| { + "failed to stub filesystem functionality [{}] in module [{export_name}]" + })?; + } + } + + // If uses_fs is specified, we must replace the required functions and they *must* be present. + if uses_fs { + for (module_name, func_name) in WASI_FS_IMPORTS_REQUIRED { + let fid = module.imports.get_func_by_name(module_name, func_name) + .with_context(|| format!("failed to find required filesystem import [{func_name}] in module [{module_name}]"))?; + module + .replace_imported_func(fid, |(body, _)| { + body.unreachable(); + }) + .with_context(|| { + "failed to stub filesystem functionality [{}] in module [{export_name}]" + })?; + } + } + Ok(()) } +/// Imports exposed by WASI for IO functionality which are allowed to be +const WASI_IO_IMPORTS: [(&str, &str); 5] = [ + ("wasi:io/streams", "read"), + ("wasi:io/streams", "blocking-write-and-flush"), + ("wasi:io/streams", "flush"), + ("wasi:io/streams", "blocking-flush"), + ("wasi:io/streams", "check-write"), +]; + +/// Imports exposed by WASI for IO functionality which *must* be present +const WASI_IO_IMPORTS_REQUIRED: [(&str, &str); 14] = [ + ("wasi:poll/poll", "drop-pollable"), + ("wasi:poll/poll", "poll-oneoff"), + ("wasi:io/streams", "blocking-read"), + ("wasi:io/streams", "skip"), + ("wasi:io/streams", "blocking-skip"), + ("wasi:io/streams", "subscribe-to-input-stream"), + ("wasi:io/streams", "drop-input-stream"), + ("wasi:io/streams", "write"), + ("wasi:io/streams", "write-zeroes"), + ("wasi:io/streams", "splice"), + ("wasi:io/streams", "blocking-splice"), + ("wasi:io/streams", "forward"), + ("wasi:io/streams", "subscribe-to-output-stream"), + ("wasi:io/streams", "drop-output-stream"), +]; + +/// Replace imported WASI functions that implement general I/O access with no-ops fn stub_io_virt(module: &mut Module) -> Result<()> { - stub_imported_func(module, "wasi:poll/poll", "drop-pollable", true)?; - stub_imported_func(module, "wasi:poll/poll", "poll-oneoff", true)?; - stub_imported_func(module, "wasi:io/streams", "read", false)?; - stub_imported_func(module, "wasi:io/streams", "blocking-read", true)?; - stub_imported_func(module, "wasi:io/streams", "skip", true)?; - stub_imported_func(module, "wasi:io/streams", "blocking-skip", true)?; - stub_imported_func(module, "wasi:io/streams", "subscribe-to-input-stream", true)?; - stub_imported_func(module, "wasi:io/streams", "drop-input-stream", true)?; - stub_imported_func(module, "wasi:io/streams", "write", true)?; - stub_imported_func(module, "wasi:io/streams", "blocking-write-and-flush", false)?; - stub_imported_func(module, "wasi:io/streams", "flush", false)?; - stub_imported_func(module, "wasi:io/streams", "blocking-flush", false)?; - stub_imported_func(module, "wasi:io/streams", "check-write", false)?; - stub_imported_func(module, "wasi:io/streams", "write-zeroes", true)?; - stub_imported_func(module, "wasi:io/streams", "splice", true)?; - stub_imported_func(module, "wasi:io/streams", "blocking-splice", true)?; - stub_imported_func(module, "wasi:io/streams", "forward", true)?; - stub_imported_func( - module, - "wasi:io/streams", - "subscribe-to-output-stream", - true, - )?; - stub_imported_func(module, "wasi:io/streams", "drop-output-stream", true)?; + // Replace the I/O functions that are allowed to be missing + for (module_name, func_name) in WASI_IO_IMPORTS { + if let Ok(fid) = module.imports.get_func_by_name(module_name, func_name) { + module + .replace_imported_func(fid, |(body, _)| { + body.unreachable(); + }) + .with_context(|| { + format!( + "failed to stub I/O functionality [{func_name}] in module [{module_name}]" + ) + })?; + } + } + + // Replace the I/O functions that *must* be present + for (module_name, func_name) in WASI_IO_IMPORTS_REQUIRED { + let fid = module + .imports + .get_func_by_name(module_name, func_name) + .with_context(|| { + format!( + "failed to find required I/O import [{func_name}] in module [{module_name}]" + ) + })?; + module + .replace_imported_func(fid, |(body, _)| { + body.unreachable(); + }) + .with_context(|| "failed to stub I/O functionality [{}] in module [{module_name}]")?; + } + Ok(()) } +/// Imports exposed by WASI for clocks functionality which are allowed to be +const WASI_CLOCKS_IMPORTS_REQUIRED: [(&str, &str); 3] = [ + ("wasi:clocks/monotonic-clock", "now"), + ("wasi:clocks/monotonic-clock", "resolution"), + ("wasi:clocks/monotonic-clock", "subscribe"), +]; + +/// Replace imported WASI functions that implement clocks access with no-ops pub(crate) fn stub_clocks_virt(module: &mut Module) -> Result<()> { - stub_imported_func(module, "wasi:clocks/monotonic-clock", "now", true)?; - stub_imported_func(module, "wasi:clocks/monotonic-clock", "resolution", true)?; - stub_imported_func(module, "wasi:clocks/monotonic-clock", "subscribe", true)?; + for (module_name, func_name) in WASI_CLOCKS_IMPORTS_REQUIRED { + let fid = module + .imports + .get_func_by_name(module_name, func_name) + .with_context(|| { + format!( + "failed to find required clocks import [{func_name}] in module [{module_name}]" + ) + })?; + module + .replace_imported_func(fid, |(body, _)| { + body.unreachable(); + }) + .with_context(|| { + "failed to stub clocks functionality [{}] in module [{export_name}]" + })?; + } Ok(()) } +/// Imports exposed by WASI for STDIO functionality which are allowed to be missing +const WASI_STDIO_IMPORTS: [(&str, &str); 8] = [ + ("wasi:cli/stdin", "get-stdin"), + ("wasi:cli/stdout", "get-stdout"), + ("wasi:cli/stderr", "get-stderr"), + ("wasi:cli/terminal-stdin", "get-terminal-stdin"), + ("wasi:cli/terminal-stdout", "get-terminal-stdout"), + ("wasi:cli/terminal-stderr", "get-terminal-stderr"), + ("wasi:cli/terminal-input", "drop-terminal-input"), + ("wasi:cli/terminal-output", "drop-terminal-output"), +]; + +/// Replace imported WASI functions that implement STDIO access with no-ops pub(crate) fn stub_stdio_virt(module: &mut Module) -> Result<()> { - stub_imported_func(module, "wasi:cli/stdin", "get-stdin", false)?; - stub_imported_func(module, "wasi:cli/stdout", "get-stdout", false)?; - stub_imported_func(module, "wasi:cli/stderr", "get-stderr", false)?; - stub_imported_func( - module, - "wasi:cli/terminal-stdin", - "get-terminal-stdin", - false, - )?; - stub_imported_func( - module, - "wasi:cli/terminal-stdout", - "get-terminal-stdout", - false, - )?; - stub_imported_func( - module, - "wasi:cli/terminal-stderr", - "get-terminal-stderr", - false, - )?; - stub_imported_func( - module, - "wasi:cli/terminal-input", - "drop-terminal-input", - false, - )?; - stub_imported_func( - module, - "wasi:cli/terminal-output", - "drop-terminal-output", - false, - )?; + for (module_name, func_name) in WASI_STDIO_IMPORTS { + if let Ok(fid) = module.imports.get_func_by_name(module_name, func_name) { + module + .replace_imported_func(fid, |(body, _)| { + body.unreachable(); + }) + .with_context(|| { + format!( + "failed to stub STDIO functionality [{func_name}] in module [{module_name}]" + ) + })?; + } + } Ok(()) } +/// Imports exposed by WASI for sockets functionality which are allowed to be missing +const WASI_SOCKETS_IMPORTS_REQUIRED: [(&str, &str); 49] = [ + ("wasi:sockets/ip-name-lookup", "resolve-addresses"), + ("wasi:sockets/ip-name-lookup", "resolve-next-address"), + ("wasi:sockets/ip-name-lookup", "drop-resolve-address-stream"), + ("wasi:sockets/ip-name-lookup", "subscribe"), + ("wasi:sockets/tcp", "start-bind"), + ("wasi:sockets/tcp", "finish-bind"), + ("wasi:sockets/tcp", "start-connect"), + ("wasi:sockets/tcp", "finish-connect"), + ("wasi:sockets/tcp", "start-listen"), + ("wasi:sockets/tcp", "finish-listen"), + ("wasi:sockets/tcp", "accept"), + ("wasi:sockets/tcp", "local-address"), + ("wasi:sockets/tcp", "remote-address"), + ("wasi:sockets/tcp", "address-family"), + ("wasi:sockets/tcp", "ipv6-only"), + ("wasi:sockets/tcp", "set-ipv6-only"), + ("wasi:sockets/tcp", "set-listen-backlog-size"), + ("wasi:sockets/tcp", "keep-alive"), + ("wasi:sockets/tcp", "set-keep-alive"), + ("wasi:sockets/tcp", "no-delay"), + ("wasi:sockets/tcp", "set-no-delay"), + ("wasi:sockets/tcp", "unicast-hop-limit"), + ("wasi:sockets/tcp", "set-unicast-hop-limit"), + ("wasi:sockets/tcp", "receive-buffer-size"), + ("wasi:sockets/tcp", "set-receive-buffer-size"), + ("wasi:sockets/tcp", "send-buffer-size"), + ("wasi:sockets/tcp", "set-send-buffer-size"), + ("wasi:sockets/tcp", "subscribe"), + ("wasi:sockets/tcp", "shutdown"), + ("wasi:sockets/tcp", "drop-tcp-socket"), + ("wasi:sockets/udp", "start-bind"), + ("wasi:sockets/udp", "finish-bind"), + ("wasi:sockets/udp", "start-connect"), + ("wasi:sockets/udp", "finish-connect"), + ("wasi:sockets/udp", "receive"), + ("wasi:sockets/udp", "send"), + ("wasi:sockets/udp", "local-address"), + ("wasi:sockets/udp", "remote-address"), + ("wasi:sockets/udp", "address-family"), + ("wasi:sockets/udp", "ipv6-only"), + ("wasi:sockets/udp", "set-ipv6-only"), + ("wasi:sockets/udp", "unicast-hop-limit"), + ("wasi:sockets/udp", "set-unicast-hop-limit"), + ("wasi:sockets/udp", "receive-buffer-size"), + ("wasi:sockets/udp", "set-receive-buffer-size"), + ("wasi:sockets/udp", "send-buffer-size"), + ("wasi:sockets/udp", "set-send-buffer-size"), + ("wasi:sockets/udp", "subscribe"), + ("wasi:sockets/udp", "drop-udp-socket"), +]; + +/// Replace imported WASI functions that implement socket access with no-ops pub(crate) fn stub_sockets_virt(module: &mut Module) -> Result<()> { - stub_imported_func( - module, - "wasi:sockets/ip-name-lookup", - "resolve-addresses", - true, - )?; - stub_imported_func( - module, - "wasi:sockets/ip-name-lookup", - "resolve-next-address", - true, - )?; - stub_imported_func( - module, - "wasi:sockets/ip-name-lookup", - "drop-resolve-address-stream", - true, - )?; - stub_imported_func(module, "wasi:sockets/ip-name-lookup", "subscribe", true)?; - - stub_imported_func(module, "wasi:sockets/tcp", "start-bind", true)?; - stub_imported_func(module, "wasi:sockets/tcp", "finish-bind", true)?; - stub_imported_func(module, "wasi:sockets/tcp", "start-connect", true)?; - stub_imported_func(module, "wasi:sockets/tcp", "finish-connect", true)?; - stub_imported_func(module, "wasi:sockets/tcp", "start-listen", true)?; - stub_imported_func(module, "wasi:sockets/tcp", "finish-listen", true)?; - stub_imported_func(module, "wasi:sockets/tcp", "accept", true)?; - stub_imported_func(module, "wasi:sockets/tcp", "local-address", true)?; - stub_imported_func(module, "wasi:sockets/tcp", "remote-address", true)?; - stub_imported_func(module, "wasi:sockets/tcp", "address-family", true)?; - stub_imported_func(module, "wasi:sockets/tcp", "ipv6-only", true)?; - stub_imported_func(module, "wasi:sockets/tcp", "set-ipv6-only", true)?; - stub_imported_func(module, "wasi:sockets/tcp", "set-listen-backlog-size", true)?; - stub_imported_func(module, "wasi:sockets/tcp", "keep-alive", true)?; - stub_imported_func(module, "wasi:sockets/tcp", "set-keep-alive", true)?; - stub_imported_func(module, "wasi:sockets/tcp", "no-delay", true)?; - stub_imported_func(module, "wasi:sockets/tcp", "set-no-delay", true)?; - stub_imported_func(module, "wasi:sockets/tcp", "unicast-hop-limit", true)?; - stub_imported_func(module, "wasi:sockets/tcp", "set-unicast-hop-limit", true)?; - stub_imported_func(module, "wasi:sockets/tcp", "receive-buffer-size", true)?; - stub_imported_func(module, "wasi:sockets/tcp", "set-receive-buffer-size", true)?; - stub_imported_func(module, "wasi:sockets/tcp", "send-buffer-size", true)?; - stub_imported_func(module, "wasi:sockets/tcp", "set-send-buffer-size", true)?; - stub_imported_func(module, "wasi:sockets/tcp", "subscribe", true)?; - stub_imported_func(module, "wasi:sockets/tcp", "shutdown", true)?; - stub_imported_func(module, "wasi:sockets/tcp", "drop-tcp-socket", true)?; - - stub_imported_func(module, "wasi:sockets/udp", "start-bind", true)?; - stub_imported_func(module, "wasi:sockets/udp", "finish-bind", true)?; - stub_imported_func(module, "wasi:sockets/udp", "start-connect", true)?; - stub_imported_func(module, "wasi:sockets/udp", "finish-connect", true)?; - stub_imported_func(module, "wasi:sockets/udp", "receive", true)?; - stub_imported_func(module, "wasi:sockets/udp", "send", true)?; - stub_imported_func(module, "wasi:sockets/udp", "local-address", true)?; - stub_imported_func(module, "wasi:sockets/udp", "remote-address", true)?; - stub_imported_func(module, "wasi:sockets/udp", "address-family", true)?; - stub_imported_func(module, "wasi:sockets/udp", "ipv6-only", true)?; - stub_imported_func(module, "wasi:sockets/udp", "set-ipv6-only", true)?; - stub_imported_func(module, "wasi:sockets/udp", "unicast-hop-limit", true)?; - stub_imported_func(module, "wasi:sockets/udp", "set-unicast-hop-limit", true)?; - stub_imported_func(module, "wasi:sockets/udp", "receive-buffer-size", true)?; - stub_imported_func(module, "wasi:sockets/udp", "set-receive-buffer-size", true)?; - stub_imported_func(module, "wasi:sockets/udp", "send-buffer-size", true)?; - stub_imported_func(module, "wasi:sockets/udp", "set-send-buffer-size", true)?; - stub_imported_func(module, "wasi:sockets/udp", "subscribe", true)?; - stub_imported_func(module, "wasi:sockets/udp", "drop-udp-socket", true)?; + for (module_name, func_name) in WASI_SOCKETS_IMPORTS_REQUIRED { + let fid = module + .imports + .get_func_by_name(module_name, func_name) + .with_context(|| { + format!( + "failed to find required clocks import [{func_name}] in module [{module_name}]" + ) + })?; + module + .replace_imported_func(fid, |(body, _)| { + body.unreachable(); + }) + .with_context(|| { + "failed to stub clocks functionality [{}] in module [{export_name}]" + })?; + } Ok(()) } -// strip functions only have to dce the virtual adapter +const WASI_FILESYSTEM_EXPORTS: [&str; 36] = [ + "wasi:filesystem/preopens#get-directories", + "wasi:filesystem/types#read-via-stream", + "wasi:filesystem/types#write-via-stream", + "wasi:filesystem/types#append-via-stream", + "wasi:filesystem/types#advise", + "wasi:filesystem/types#sync-data", + "wasi:filesystem/types#get-flags", + "wasi:filesystem/types#get-type", + "wasi:filesystem/types#set-size", + "wasi:filesystem/types#set-times", + "wasi:filesystem/types#read", + "wasi:filesystem/types#write", + "wasi:filesystem/types#read-directory", + "wasi:filesystem/types#sync", + "wasi:filesystem/types#create-directory-at", + "wasi:filesystem/types#stat", + "wasi:filesystem/types#stat-at", + "wasi:filesystem/types#set-times-at", + "wasi:filesystem/types#link-at", + "wasi:filesystem/types#open-at", + "wasi:filesystem/types#readlink-at", + "wasi:filesystem/types#remove-directory-at", + "wasi:filesystem/types#rename-at", + "wasi:filesystem/types#symlink-at", + "wasi:filesystem/types#access-at", + "wasi:filesystem/types#unlink-file-at", + "wasi:filesystem/types#change-file-permissions-at", + "wasi:filesystem/types#change-directory-permissions-at", + "wasi:filesystem/types#lock-shared", + "wasi:filesystem/types#lock-exclusive", + "wasi:filesystem/types#try-lock-shared", + "wasi:filesystem/types#try-lock-exclusive", + "wasi:filesystem/types#unlock", + "wasi:filesystem/types#drop-descriptor", + "wasi:filesystem/types#read-directory-entry", + "wasi:filesystem/types#drop-directory-entry-stream", +]; + +/// Strip exported WASI functions that implement filesystem access pub(crate) fn strip_fs_virt(module: &mut Module) -> Result<()> { stub_fs_virt(module, false)?; - remove_exported_func(module, "wasi:filesystem/preopens#get-directories")?; - - remove_exported_func(module, "wasi:filesystem/types#read-via-stream")?; - remove_exported_func(module, "wasi:filesystem/types#write-via-stream")?; - remove_exported_func(module, "wasi:filesystem/types#append-via-stream")?; - remove_exported_func(module, "wasi:filesystem/types#advise")?; - remove_exported_func(module, "wasi:filesystem/types#sync-data")?; - remove_exported_func(module, "wasi:filesystem/types#get-flags")?; - remove_exported_func(module, "wasi:filesystem/types#get-type")?; - remove_exported_func(module, "wasi:filesystem/types#set-size")?; - remove_exported_func(module, "wasi:filesystem/types#set-times")?; - remove_exported_func(module, "wasi:filesystem/types#read")?; - remove_exported_func(module, "wasi:filesystem/types#write")?; - remove_exported_func(module, "wasi:filesystem/types#read-directory")?; - remove_exported_func(module, "wasi:filesystem/types#sync")?; - remove_exported_func(module, "wasi:filesystem/types#create-directory-at")?; - remove_exported_func(module, "wasi:filesystem/types#stat")?; - remove_exported_func(module, "wasi:filesystem/types#stat-at")?; - remove_exported_func(module, "wasi:filesystem/types#set-times-at")?; - remove_exported_func(module, "wasi:filesystem/types#link-at")?; - remove_exported_func(module, "wasi:filesystem/types#open-at")?; - remove_exported_func(module, "wasi:filesystem/types#readlink-at")?; - remove_exported_func(module, "wasi:filesystem/types#remove-directory-at")?; - remove_exported_func(module, "wasi:filesystem/types#rename-at")?; - remove_exported_func(module, "wasi:filesystem/types#symlink-at")?; - remove_exported_func(module, "wasi:filesystem/types#access-at")?; - remove_exported_func(module, "wasi:filesystem/types#unlink-file-at")?; - remove_exported_func(module, "wasi:filesystem/types#change-file-permissions-at")?; - remove_exported_func( - module, - "wasi:filesystem/types#change-directory-permissions-at", - )?; - remove_exported_func(module, "wasi:filesystem/types#lock-shared")?; - remove_exported_func(module, "wasi:filesystem/types#lock-exclusive")?; - remove_exported_func(module, "wasi:filesystem/types#try-lock-shared")?; - remove_exported_func(module, "wasi:filesystem/types#try-lock-exclusive")?; - remove_exported_func(module, "wasi:filesystem/types#unlock")?; - remove_exported_func(module, "wasi:filesystem/types#drop-descriptor")?; - remove_exported_func(module, "wasi:filesystem/types#read-directory-entry")?; - remove_exported_func(module, "wasi:filesystem/types#drop-directory-entry-stream")?; + + for export_name in WASI_FILESYSTEM_EXPORTS { + module.exports.delete_func_by_name(export_name)?; + } + Ok(()) } +/// Exported functions related to WASI clocks +const WASI_CLOCK_EXPORTS: [&str; 3] = [ + "wasi:clocks/monotonic-clock#now", + "wasi:clocks/monotonic-clock#resolution", + "wasi:clocks/monotonic-clock#subscribe", +]; + +/// Strip exported WASI functions that implement clock access pub(crate) fn strip_clocks_virt(module: &mut Module) -> Result<()> { stub_clocks_virt(module)?; - remove_exported_func(module, "wasi:clocks/monotonic-clock#now")?; - remove_exported_func(module, "wasi:clocks/monotonic-clock#resolution")?; - remove_exported_func(module, "wasi:clocks/monotonic-clock#subscribe")?; + for export_name in WASI_CLOCK_EXPORTS { + module + .exports + .delete_func_by_name(export_name) + .with_context(|| format!("failed to strip clocks function [{export_name}]"))?; + } Ok(()) } +/// Exported functions related to WASI http +const WASI_HTTP_EXPORTS: [&str; 32] = [ + "wasi:http/types#drop-fields", + "wasi:http/types#new-fields", + "wasi:http/types#fields-get", + "wasi:http/types#fields-set", + "wasi:http/types#fields-delete", + "wasi:http/types#fields-append", + "wasi:http/types#fields-entries", + "wasi:http/types#fields-clone", + "wasi:http/types#finish-incoming-stream", + "wasi:http/types#finish-outgoing-stream", + "wasi:http/types#drop-incoming-request", + "wasi:http/types#drop-outgoing-request", + "wasi:http/types#incoming-request-method", + "wasi:http/types#incoming-request-path-with-query", + "wasi:http/types#incoming-request-scheme", + "wasi:http/types#incoming-request-authority", + "wasi:http/types#incoming-request-headers", + "wasi:http/types#incoming-request-consume", + "wasi:http/types#new-outgoing-request", + "wasi:http/types#outgoing-request-write", + "wasi:http/types#drop-response-outparam", + "wasi:http/types#set-response-outparam", + "wasi:http/types#drop-incoming-response", + "wasi:http/types#drop-outgoing-response", + "wasi:http/types#incoming-response-status", + "wasi:http/types#incoming-response-headers", + "wasi:http/types#incoming-response-consume", + "wasi:http/types#new-outgoing-response", + "wasi:http/types#outgoing-response-write", + "wasi:http/types#drop-future-incoming-response", + "wasi:http/types#future-incoming-response-get", + "wasi:http/types#listen-to-future-incoming-response", +]; + +/// Strip exported WASI functions that implement HTTP access pub(crate) fn strip_http_virt(module: &mut Module) -> Result<()> { stub_http_virt(module)?; - remove_exported_func(module, "wasi:http/types#drop-fields")?; - remove_exported_func(module, "wasi:http/types#new-fields")?; - remove_exported_func(module, "wasi:http/types#fields-get")?; - remove_exported_func(module, "wasi:http/types#fields-set")?; - remove_exported_func(module, "wasi:http/types#fields-delete")?; - remove_exported_func(module, "wasi:http/types#fields-append")?; - remove_exported_func(module, "wasi:http/types#fields-entries")?; - remove_exported_func(module, "wasi:http/types#fields-clone")?; - remove_exported_func(module, "wasi:http/types#finish-incoming-stream")?; - remove_exported_func(module, "wasi:http/types#finish-outgoing-stream")?; - remove_exported_func(module, "wasi:http/types#drop-incoming-request")?; - remove_exported_func(module, "wasi:http/types#drop-outgoing-request")?; - remove_exported_func(module, "wasi:http/types#incoming-request-method")?; - remove_exported_func(module, "wasi:http/types#incoming-request-path-with-query")?; - remove_exported_func(module, "wasi:http/types#incoming-request-scheme")?; - remove_exported_func(module, "wasi:http/types#incoming-request-authority")?; - remove_exported_func(module, "wasi:http/types#incoming-request-headers")?; - remove_exported_func(module, "wasi:http/types#incoming-request-consume")?; - remove_exported_func(module, "wasi:http/types#new-outgoing-request")?; - remove_exported_func(module, "wasi:http/types#outgoing-request-write")?; - remove_exported_func(module, "wasi:http/types#drop-response-outparam")?; - remove_exported_func(module, "wasi:http/types#set-response-outparam")?; - remove_exported_func(module, "wasi:http/types#drop-incoming-response")?; - remove_exported_func(module, "wasi:http/types#drop-outgoing-response")?; - remove_exported_func(module, "wasi:http/types#incoming-response-status")?; - remove_exported_func(module, "wasi:http/types#incoming-response-headers")?; - remove_exported_func(module, "wasi:http/types#incoming-response-consume")?; - remove_exported_func(module, "wasi:http/types#new-outgoing-response")?; - remove_exported_func(module, "wasi:http/types#outgoing-response-write")?; - remove_exported_func(module, "wasi:http/types#drop-future-incoming-response")?; - remove_exported_func(module, "wasi:http/types#future-incoming-response-get")?; - remove_exported_func(module, "wasi:http/types#listen-to-future-incoming-response")?; + for export_name in WASI_HTTP_EXPORTS { + module + .exports + .delete_func_by_name(export_name) + .with_context(|| format!("failed to strip HTTP function [{export_name}]"))?; + } Ok(()) } +/// Imports exposed by WASI for HTTP functionality +const WASI_HTTP_IMPORTS: [(&str, &str); 32] = [ + ("wasi:http/types", "drop-fields"), + ("wasi:http/types", "new-fields"), + ("wasi:http/types", "fields-get"), + ("wasi:http/types", "fields-set"), + ("wasi:http/types", "fields-delete"), + ("wasi:http/types", "fields-append"), + ("wasi:http/types", "fields-entries"), + ("wasi:http/types", "fields-clone"), + ("wasi:http/types", "finish-incoming-stream"), + ("wasi:http/types", "finish-outgoing-stream"), + ("wasi:http/types", "drop-incoming-request"), + ("wasi:http/types", "drop-outgoing-request"), + ("wasi:http/types", "incoming-request-method"), + ("wasi:http/types", "incoming-request-path-with-query"), + ("wasi:http/types", "incoming-request-scheme"), + ("wasi:http/types", "incoming-request-authority"), + ("wasi:http/types", "incoming-request-headers"), + ("wasi:http/types", "incoming-request-consume"), + ("wasi:http/types", "new-outgoing-request"), + ("wasi:http/types", "outgoing-request-write"), + ("wasi:http/types", "drop-response-outparam"), + ("wasi:http/types", "set-response-outparam"), + ("wasi:http/types", "drop-incoming-response"), + ("wasi:http/types", "drop-outgoing-response"), + ("wasi:http/types", "incoming-response-status"), + ("wasi:http/types", "incoming-response-headers"), + ("wasi:http/types", "incoming-response-consume"), + ("wasi:http/types", "new-outgoing-response"), + ("wasi:http/types", "outgoing-response-write"), + ("wasi:http/types", "drop-future-incoming-response"), + ("wasi:http/types", "future-incoming-response-get"), + ("wasi:http/types", "listen-to-future-incoming-response"), +]; + +/// Replace imported WASI functions that implement HTTP access with no-ops pub(crate) fn stub_http_virt(module: &mut Module) -> Result<()> { - stub_imported_func(module, "wasi:http/types", "drop-fields", false)?; - stub_imported_func(module, "wasi:http/types", "new-fields", false)?; - stub_imported_func(module, "wasi:http/types", "fields-get", false)?; - stub_imported_func(module, "wasi:http/types", "fields-set", false)?; - stub_imported_func(module, "wasi:http/types", "fields-delete", false)?; - stub_imported_func(module, "wasi:http/types", "fields-append", false)?; - stub_imported_func(module, "wasi:http/types", "fields-entries", false)?; - stub_imported_func(module, "wasi:http/types", "fields-clone", false)?; - stub_imported_func(module, "wasi:http/types", "finish-incoming-stream", false)?; - stub_imported_func(module, "wasi:http/types", "finish-outgoing-stream", false)?; - stub_imported_func(module, "wasi:http/types", "drop-incoming-request", false)?; - stub_imported_func(module, "wasi:http/types", "drop-outgoing-request", false)?; - stub_imported_func(module, "wasi:http/types", "incoming-request-method", false)?; - stub_imported_func( - module, - "wasi:http/types", - "incoming-request-path-with-query", - false, - )?; - stub_imported_func(module, "wasi:http/types", "incoming-request-scheme", false)?; - stub_imported_func( - module, - "wasi:http/types", - "incoming-request-authority", - false, - )?; - stub_imported_func(module, "wasi:http/types", "incoming-request-headers", false)?; - stub_imported_func(module, "wasi:http/types", "incoming-request-consume", false)?; - stub_imported_func(module, "wasi:http/types", "new-outgoing-request", false)?; - stub_imported_func(module, "wasi:http/types", "outgoing-request-write", false)?; - stub_imported_func(module, "wasi:http/types", "drop-response-outparam", false)?; - stub_imported_func(module, "wasi:http/types", "set-response-outparam", false)?; - stub_imported_func(module, "wasi:http/types", "drop-incoming-response", false)?; - stub_imported_func(module, "wasi:http/types", "drop-outgoing-response", false)?; - stub_imported_func(module, "wasi:http/types", "incoming-response-status", false)?; - stub_imported_func( - module, - "wasi:http/types", - "incoming-response-headers", - false, - )?; - stub_imported_func( - module, - "wasi:http/types", - "incoming-response-consume", - false, - )?; - stub_imported_func(module, "wasi:http/types", "new-outgoing-response", false)?; - stub_imported_func(module, "wasi:http/types", "outgoing-response-write", false)?; - stub_imported_func( - module, - "wasi:http/types", - "drop-future-incoming-response", - false, - )?; - stub_imported_func( - module, - "wasi:http/types", - "future-incoming-response-get", - false, - )?; - stub_imported_func( - module, - "wasi:http/types", - "listen-to-future-incoming-response", - false, - )?; + for (module_name, func_name) in WASI_HTTP_IMPORTS { + if let Ok(fid) = module.imports.get_func_by_name(module_name, func_name) { + module + .replace_imported_func(fid, |(body, _)| { + body.unreachable(); + }) + .with_context(|| { + "failed to stub http functionality [{}] in module [{export_name}]" + })?; + } + } Ok(()) } +/// Exported functions related to STDIO +const WASI_STDIO_EXPORTS: [&str; 8] = [ + "wasi:cli/stdin#get-stdin", + "wasi:cli/stdout#get-stdout", + "wasi:cli/stderr#get-stderr", + "wasi:cli/terminal-stdin#get-terminal-stdin", + "wasi:cli/terminal-stdout#get-terminal-stdout", + "wasi:cli/terminal-stderr#get-terminal-stderr", + "wasi:cli/terminal-input#drop-terminal-input", + "wasi:cli/terminal-output#drop-terminal-output", +]; + +/// Strip exported WASI functions that implement standard I/O (stdin, stdout, etc) access pub(crate) fn strip_stdio_virt(module: &mut Module) -> Result<()> { stub_stdio_virt(module)?; - remove_exported_func(module, "wasi:cli/stdin#get-stdin")?; - remove_exported_func(module, "wasi:cli/stdout#get-stdout")?; - remove_exported_func(module, "wasi:cli/stderr#get-stderr")?; - remove_exported_func(module, "wasi:cli/terminal-stdin#get-terminal-stdin")?; - remove_exported_func(module, "wasi:cli/terminal-stdout#get-terminal-stdout")?; - remove_exported_func(module, "wasi:cli/terminal-stderr#get-terminal-stderr")?; - remove_exported_func(module, "wasi:cli/terminal-input#drop-terminal-input")?; - remove_exported_func(module, "wasi:cli/terminal-output#drop-terminal-output")?; + for export_name in WASI_STDIO_EXPORTS { + module + .exports + .delete_func_by_name(export_name) + .with_context(|| format!("failed to strip std I/O function [{export_name}]"))?; + } Ok(()) } +/// Exported functions related to IO +const WASI_IO_EXPORTS: [&str; 19] = [ + "wasi:io/streams#read", + "wasi:io/streams#blocking-read", + "wasi:io/streams#skip", + "wasi:io/streams#blocking-skip", + "wasi:io/streams#subscribe-to-input-stream", + "wasi:io/streams#drop-input-stream", + "wasi:io/streams#write", + "wasi:io/streams#blocking-write-and-flush", + "wasi:io/streams#flush", + "wasi:io/streams#blocking-flush", + "wasi:io/streams#check-write", + "wasi:io/streams#write-zeroes", + "wasi:io/streams#splice", + "wasi:io/streams#blocking-splice", + "wasi:io/streams#forward", + "wasi:io/streams#subscribe-to-output-stream", + "wasi:io/streams#drop-output-stream", + "wasi:poll/poll#drop-pollable", + "wasi:poll/poll#poll-oneoff", +]; + +/// Strip exported WASI functions that implement IO (streams, polling) access pub(crate) fn strip_io_virt(module: &mut Module) -> Result<()> { stub_io_virt(module)?; - remove_exported_func(module, "wasi:io/streams#read")?; - remove_exported_func(module, "wasi:io/streams#blocking-read")?; - remove_exported_func(module, "wasi:io/streams#skip")?; - remove_exported_func(module, "wasi:io/streams#blocking-skip")?; - remove_exported_func(module, "wasi:io/streams#subscribe-to-input-stream")?; - remove_exported_func(module, "wasi:io/streams#drop-input-stream")?; - remove_exported_func(module, "wasi:io/streams#write")?; - remove_exported_func(module, "wasi:io/streams#blocking-write-and-flush")?; - remove_exported_func(module, "wasi:io/streams#flush")?; - remove_exported_func(module, "wasi:io/streams#blocking-flush")?; - remove_exported_func(module, "wasi:io/streams#check-write")?; - remove_exported_func(module, "wasi:io/streams#write-zeroes")?; - remove_exported_func(module, "wasi:io/streams#splice")?; - remove_exported_func(module, "wasi:io/streams#blocking-splice")?; - remove_exported_func(module, "wasi:io/streams#forward")?; - remove_exported_func(module, "wasi:io/streams#subscribe-to-output-stream")?; - remove_exported_func(module, "wasi:io/streams#drop-output-stream")?; - - remove_exported_func(module, "wasi:poll/poll#drop-pollable")?; - remove_exported_func(module, "wasi:poll/poll#poll-oneoff")?; + for export_name in WASI_IO_EXPORTS { + module + .exports + .delete_func_by_name(export_name) + .with_context(|| format!("failed to strip general I/O function [{export_name}]"))?; + } Ok(()) } +/// Exported functions related to sockets +const WASI_SOCKETS_EXPORTS: [&str; 49] = [ + "wasi:sockets/ip-name-lookup#resolve-addresses", + "wasi:sockets/ip-name-lookup#resolve-next-address", + "wasi:sockets/ip-name-lookup#drop-resolve-address-stream", + "wasi:sockets/ip-name-lookup#subscribe", + "wasi:sockets/tcp#start-bind", + "wasi:sockets/tcp#finish-bind", + "wasi:sockets/tcp#start-connect", + "wasi:sockets/tcp#finish-connect", + "wasi:sockets/tcp#start-listen", + "wasi:sockets/tcp#finish-listen", + "wasi:sockets/tcp#accept", + "wasi:sockets/tcp#local-address", + "wasi:sockets/tcp#remote-address", + "wasi:sockets/tcp#address-family", + "wasi:sockets/tcp#ipv6-only", + "wasi:sockets/tcp#set-ipv6-only", + "wasi:sockets/tcp#set-listen-backlog-size", + "wasi:sockets/tcp#keep-alive", + "wasi:sockets/tcp#set-keep-alive", + "wasi:sockets/tcp#no-delay", + "wasi:sockets/tcp#set-no-delay", + "wasi:sockets/tcp#unicast-hop-limit", + "wasi:sockets/tcp#set-unicast-hop-limit", + "wasi:sockets/tcp#receive-buffer-size", + "wasi:sockets/tcp#set-receive-buffer-size", + "wasi:sockets/tcp#send-buffer-size", + "wasi:sockets/tcp#set-send-buffer-size", + "wasi:sockets/tcp#subscribe", + "wasi:sockets/tcp#shutdown", + "wasi:sockets/tcp#drop-tcp-socket", + "wasi:sockets/udp#start-bind", + "wasi:sockets/udp#finish-bind", + "wasi:sockets/udp#start-connect", + "wasi:sockets/udp#finish-connect", + "wasi:sockets/udp#receive", + "wasi:sockets/udp#send", + "wasi:sockets/udp#local-address", + "wasi:sockets/udp#remote-address", + "wasi:sockets/udp#address-family", + "wasi:sockets/udp#ipv6-only", + "wasi:sockets/udp#set-ipv6-only", + "wasi:sockets/udp#unicast-hop-limit", + "wasi:sockets/udp#set-unicast-hop-limit", + "wasi:sockets/udp#receive-buffer-size", + "wasi:sockets/udp#set-receive-buffer-size", + "wasi:sockets/udp#send-buffer-size", + "wasi:sockets/udp#set-send-buffer-size", + "wasi:sockets/udp#subscribe", + "wasi:sockets/udp#drop-udp-socket", +]; + +/// Strip exported WASI functions that implement sockets access pub(crate) fn strip_sockets_virt(module: &mut Module) -> Result<()> { stub_sockets_virt(module)?; - remove_exported_func(module, "wasi:sockets/ip-name-lookup#resolve-addresses")?; - remove_exported_func(module, "wasi:sockets/ip-name-lookup#resolve-next-address")?; - remove_exported_func( - module, - "wasi:sockets/ip-name-lookup#drop-resolve-address-stream", - )?; - remove_exported_func(module, "wasi:sockets/ip-name-lookup#subscribe")?; - - remove_exported_func(module, "wasi:sockets/tcp#start-bind")?; - remove_exported_func(module, "wasi:sockets/tcp#finish-bind")?; - remove_exported_func(module, "wasi:sockets/tcp#start-connect")?; - remove_exported_func(module, "wasi:sockets/tcp#finish-connect")?; - remove_exported_func(module, "wasi:sockets/tcp#start-listen")?; - remove_exported_func(module, "wasi:sockets/tcp#finish-listen")?; - remove_exported_func(module, "wasi:sockets/tcp#accept")?; - remove_exported_func(module, "wasi:sockets/tcp#local-address")?; - remove_exported_func(module, "wasi:sockets/tcp#remote-address")?; - remove_exported_func(module, "wasi:sockets/tcp#address-family")?; - remove_exported_func(module, "wasi:sockets/tcp#ipv6-only")?; - remove_exported_func(module, "wasi:sockets/tcp#set-ipv6-only")?; - remove_exported_func(module, "wasi:sockets/tcp#set-listen-backlog-size")?; - remove_exported_func(module, "wasi:sockets/tcp#keep-alive")?; - remove_exported_func(module, "wasi:sockets/tcp#set-keep-alive")?; - remove_exported_func(module, "wasi:sockets/tcp#no-delay")?; - remove_exported_func(module, "wasi:sockets/tcp#set-no-delay")?; - remove_exported_func(module, "wasi:sockets/tcp#unicast-hop-limit")?; - remove_exported_func(module, "wasi:sockets/tcp#set-unicast-hop-limit")?; - remove_exported_func(module, "wasi:sockets/tcp#receive-buffer-size")?; - remove_exported_func(module, "wasi:sockets/tcp#set-receive-buffer-size")?; - remove_exported_func(module, "wasi:sockets/tcp#send-buffer-size")?; - remove_exported_func(module, "wasi:sockets/tcp#set-send-buffer-size")?; - remove_exported_func(module, "wasi:sockets/tcp#subscribe")?; - remove_exported_func(module, "wasi:sockets/tcp#shutdown")?; - remove_exported_func(module, "wasi:sockets/tcp#drop-tcp-socket")?; - - remove_exported_func(module, "wasi:sockets/udp#start-bind")?; - remove_exported_func(module, "wasi:sockets/udp#finish-bind")?; - remove_exported_func(module, "wasi:sockets/udp#start-connect")?; - remove_exported_func(module, "wasi:sockets/udp#finish-connect")?; - remove_exported_func(module, "wasi:sockets/udp#receive")?; - remove_exported_func(module, "wasi:sockets/udp#send")?; - remove_exported_func(module, "wasi:sockets/udp#local-address")?; - remove_exported_func(module, "wasi:sockets/udp#remote-address")?; - remove_exported_func(module, "wasi:sockets/udp#address-family")?; - remove_exported_func(module, "wasi:sockets/udp#ipv6-only")?; - remove_exported_func(module, "wasi:sockets/udp#set-ipv6-only")?; - remove_exported_func(module, "wasi:sockets/udp#unicast-hop-limit")?; - remove_exported_func(module, "wasi:sockets/udp#set-unicast-hop-limit")?; - remove_exported_func(module, "wasi:sockets/udp#receive-buffer-size")?; - remove_exported_func(module, "wasi:sockets/udp#set-receive-buffer-size")?; - remove_exported_func(module, "wasi:sockets/udp#send-buffer-size")?; - remove_exported_func(module, "wasi:sockets/udp#set-send-buffer-size")?; - remove_exported_func(module, "wasi:sockets/udp#subscribe")?; - remove_exported_func(module, "wasi:sockets/udp#drop-udp-socket")?; + for export_name in WASI_SOCKETS_EXPORTS { + module.exports.delete_func_by_name(export_name)?; + } Ok(()) } diff --git a/src/walrus_ops.rs b/src/walrus_ops.rs index 9a60630..c9386d6 100644 --- a/src/walrus_ops.rs +++ b/src/walrus_ops.rs @@ -1,8 +1,7 @@ use anyhow::{bail, Context, Result}; use walrus::{ - ir::Value, ActiveData, ActiveDataLocation, Data, DataKind, ExportItem, Function, - FunctionBuilder, FunctionId, FunctionKind, GlobalKind, ImportKind, ImportedFunction, InitExpr, - MemoryId, Module, ValType, + ir::Value, ActiveData, ActiveDataLocation, Data, DataKind, GlobalKind, InitExpr, MemoryId, + Module, }; pub(crate) fn get_active_data_start(data: &Data, mem: MemoryId) -> Result { @@ -49,15 +48,6 @@ pub(crate) fn get_active_data_segment( Ok((module.data.get_mut(data_id), offset)) } -pub(crate) fn get_memory_id(module: &Module) -> Result { - let mut mem_iter = module.memories.iter(); - let memory = mem_iter.next().context("Module does not export a memory")?; - if mem_iter.next().is_some() { - bail!("Multiple memories unsupported") - } - Ok(memory.id()) -} - pub(crate) fn get_stack_global(module: &Module) -> Result { let stack_global_id = module .globals @@ -96,100 +86,3 @@ pub(crate) fn bump_stack_global(module: &mut Module, offset: i32) -> Result *stack_value = new_stack_value; Ok(new_stack_value as u32) } - -pub(crate) fn get_exported_func(module: &mut Module, name: &str) -> Result { - let exported_fn = module - .exports - .iter() - .find(|expt| expt.name == name) - .with_context(|| format!("Unable to find export '{name}'"))?; - let ExportItem::Function(fid) = exported_fn.item else { - bail!("{name} not a function"); - }; - Ok(fid) -} - -pub(crate) fn add_stub_exported_func( - module: &mut Module, - export_name: &str, - params: Vec, - results: Vec, -) -> Result<()> { - let exported_fn = module.exports.iter().find(|expt| expt.name == export_name); - - let mut builder = FunctionBuilder::new(&mut module.types, ¶ms, &results); - builder.func_body().unreachable(); - let local_func = builder.local_func(vec![]); - let fid = module.funcs.add_local(local_func); - - // if it exists, replace it - if let Some(exported_fn) = exported_fn { - let export = module.exports.get_mut(exported_fn.id()); - export.item = ExportItem::Function(fid); - } else { - module.exports.add(export_name, ExportItem::Function(fid)); - } - - Ok(()) -} - -pub(crate) fn stub_imported_func( - module: &mut Module, - import_module: &str, - import_name: &str, - throw_if_not_found: bool, -) -> Result<()> { - let imported_fn = match module - .imports - .iter() - .find(|impt| impt.module == import_module && impt.name == import_name) - { - Some(found) => found, - None => { - if throw_if_not_found { - bail!("Unable to find import {import_module}#{import_name} to stub"); - } else { - return Ok(()); - } - } - }; - - let ImportKind::Function(fid) = imported_fn.kind else { - bail!("Unable to stub import {import_module}#{import_name}, as it is not an imported function"); - }; - let Function { - kind: FunctionKind::Import(ImportedFunction { ty: tid, .. }), - .. - } = module.funcs.get(fid) - else { - bail!("Unable to stub import {import_module}#{import_name}, as it is not an imported function"); - }; - - let ty = module.types.get(*tid); - let (params, results) = (ty.params().to_vec(), ty.results().to_vec()); - - let mut builder = FunctionBuilder::new(&mut module.types, ¶ms, &results); - builder.func_body().unreachable(); - let local_func = builder.local_func(vec![]); - - // substitute the local func into the imported func id - let func = module.funcs.get_mut(fid); - func.kind = FunctionKind::Local(local_func); - - // remove the import - module.imports.delete(imported_fn.id()); - - Ok(()) -} - -pub(crate) fn remove_exported_func(module: &mut Module, export_name: &str) -> Result<()> { - let exported_fn = module - .exports - .iter() - .find(|expt| expt.name == export_name) - .with_context(|| format!("Unable to find export {export_name}"))?; - - module.exports.delete(exported_fn.id()); - - Ok(()) -} diff --git a/tests/virt.rs b/tests/virt.rs index 8d841c1..4cdc06d 100644 --- a/tests/virt.rs +++ b/tests/virt.rs @@ -271,7 +271,7 @@ async fn virt_test() -> Result<()> { } } - if let Some(expect_stdout) = &test.expect.stdout { + if let Some(_expect_stdout) = &test.expect.stdout { // todo: expectation pending wasmtime stream flushing instance.call_test_stdio(&mut store).await?; }