fix(runtime): update for wasmtime-wasi 30 and fix seccomp filter

- IoView/WasiView split: implement IoView for State, remove table()
  from WasiView impl
- preopened_dir: new signature takes host path and guest path directly
- LinkerInstance::func_wrap returns Result in wasmtime 30; use a
  variable for the clipboard LinkerInstance
- Set PR_SET_NO_NEW_PRIVS before applying the seccomp filter
- Unconditional syscall block uses empty Vec<SeccompRule>
This commit is contained in:
Marco Allegretti 2026-03-12 20:03:33 +01:00
parent e3504c324b
commit 54b5fb662b

View file

@ -97,15 +97,14 @@ fn run_module(
preopen: &[(String, String)], preopen: &[(String, String)],
ipc_socket: Option<&str>, ipc_socket: Option<&str>,
) -> anyhow::Result<()> { ) -> anyhow::Result<()> {
use cap_std::{ambient_authority, fs::Dir};
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use wasmtime::{ use wasmtime::{
Config, Engine, Store, Config, Engine, Store,
component::{Component, Linker}, component::{Component, Linker},
}; };
use wasmtime_wasi::{ use wasmtime_wasi::{
DirPerms, FilePerms, ResourceTable, WasiCtx, WasiCtxBuilder, WasiView, add_to_linker_sync, DirPerms, FilePerms, IoView, ResourceTable, WasiCtx, WasiCtxBuilder, WasiView,
bindings::sync::Command, add_to_linker_sync, bindings::sync::Command,
}; };
struct IpcState { struct IpcState {
@ -168,13 +167,16 @@ fn run_module(
ipc: Arc<Mutex<Option<IpcState>>>, ipc: Arc<Mutex<Option<IpcState>>>,
} }
impl IoView for State {
fn table(&mut self) -> &mut ResourceTable {
&mut self.table
}
}
impl WasiView for State { impl WasiView for State {
fn ctx(&mut self) -> &mut WasiCtx { fn ctx(&mut self) -> &mut WasiCtx {
&mut self.ctx &mut self.ctx
} }
fn table(&mut self) -> &mut ResourceTable {
&mut self.table
}
} }
let mut config = Config::new(); let mut config = Config::new();
@ -267,27 +269,31 @@ fn run_module(
) )
.context("define weft:app/notifications#notify")?; .context("define weft:app/notifications#notify")?;
linker {
.instance("weft:app/clipboard@0.1.0") let mut clipboard = linker
.context("define weft:app/clipboard instance")? .instance("weft:app/clipboard@0.1.0")
.func_wrap( .context("define weft:app/clipboard instance")?;
"read", clipboard
|_: wasmtime::StoreContextMut<'_, State>, .func_wrap(
()| "read",
-> wasmtime::Result<(Result<String, String>,)> { |_: wasmtime::StoreContextMut<'_, State>,
Ok((host_clipboard_read(),)) ()|
}, -> wasmtime::Result<(Result<String, String>,)> {
) Ok((host_clipboard_read(),))
.context("define weft:app/clipboard#read")? },
.func_wrap( )
"write", .context("define weft:app/clipboard#read")?;
|_: wasmtime::StoreContextMut<'_, State>, clipboard
(text,): (String,)| .func_wrap(
-> wasmtime::Result<(Result<(), String>,)> { "write",
Ok((host_clipboard_write(&text),)) |_: wasmtime::StoreContextMut<'_, State>,
}, (text,): (String,)|
) -> wasmtime::Result<(Result<(), String>,)> {
.context("define weft:app/clipboard#write")?; Ok((host_clipboard_write(&text),))
},
)
.context("define weft:app/clipboard#write")?;
}
let mut ctx_builder = WasiCtxBuilder::new(); let mut ctx_builder = WasiCtxBuilder::new();
ctx_builder.inherit_stdout().inherit_stderr(); ctx_builder.inherit_stdout().inherit_stderr();
@ -306,9 +312,9 @@ fn run_module(
} }
for (host_path, guest_path) in preopen { for (host_path, guest_path) in preopen {
let dir = Dir::open_ambient_dir(host_path, ambient_authority()) ctx_builder
.with_context(|| format!("open preopen dir {host_path}"))?; .preopened_dir(host_path, guest_path, DirPerms::all(), FilePerms::all())
ctx_builder.preopened_dir(dir, DirPerms::all(), FilePerms::all(), guest_path); .with_context(|| format!("preopen dir {host_path}"))?;
} }
let ctx = ctx_builder.build(); let ctx = ctx_builder.build();
@ -456,7 +462,7 @@ fn apply_seccomp_filter() -> anyhow::Result<()> {
let mut rules: BTreeMap<i64, Vec<SeccompRule>> = BTreeMap::new(); let mut rules: BTreeMap<i64, Vec<SeccompRule>> = BTreeMap::new();
for &syscall in blocked { for &syscall in blocked {
rules.insert(syscall, vec![SeccompRule::new(vec![])?]); rules.insert(syscall, vec![]);
} }
let filter = SeccompFilter::new( let filter = SeccompFilter::new(
@ -466,6 +472,8 @@ fn apply_seccomp_filter() -> anyhow::Result<()> {
arch, arch,
)?; )?;
let bpf: BpfProgram = filter.try_into()?; let bpf: BpfProgram = filter.try_into()?;
let ret = unsafe { libc::prctl(libc::PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) };
anyhow::ensure!(ret == 0, "prctl PR_SET_NO_NEW_PRIVS failed: {}", std::io::Error::last_os_error());
seccompiler::apply_filter(&bpf)?; seccompiler::apply_filter(&bpf)?;
Ok(()) Ok(())
} }