kobako 0.28.0 → 0.29.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.release-please-manifest.json +1 -1
- data/CHANGELOG.md +170 -0
- data/Cargo.lock +111 -82
- data/README.md +154 -36
- data/ROADMAP.md +5 -0
- data/SECURITY.md +1 -1
- data/crates/kobako-runtime/CHANGELOG.md +86 -0
- data/crates/kobako-runtime/Cargo.toml +27 -6
- data/crates/kobako-runtime/README.md +13 -8
- data/crates/kobako-runtime/src/dispatch.rs +8 -0
- data/crates/kobako-runtime/src/filesystem/directory/spelling.rs +194 -0
- data/crates/kobako-runtime/src/filesystem/directory.rs +1082 -0
- data/crates/kobako-runtime/src/filesystem/memory.rs +1100 -0
- data/crates/kobako-runtime/src/filesystem/overlay/exclusive.rs +88 -0
- data/crates/kobako-runtime/src/filesystem/overlay/stack.rs +808 -0
- data/crates/kobako-runtime/src/filesystem/overlay.rs +1955 -0
- data/crates/kobako-runtime/src/filesystem/path.rs +60 -0
- data/crates/kobako-runtime/src/filesystem/temporary.rs +167 -0
- data/crates/kobako-runtime/src/filesystem.rs +392 -0
- data/crates/kobako-runtime/src/grant.rs +20 -0
- data/crates/kobako-runtime/src/lib.rs +11 -1
- data/crates/kobako-runtime/src/mount.rs +178 -0
- data/crates/kobako-runtime/src/profile.rs +4 -4
- data/crates/kobako-runtime/src/runtime.rs +12 -0
- data/crates/kobako-runtime/src/snapshot.rs +20 -5
- data/crates/kobako-runtime/src/yielder.rs +11 -6
- data/crates/kobako-transport/CHANGELOG.md +17 -0
- data/crates/kobako-transport/Cargo.toml +1 -1
- data/crates/kobako-transport/README.md +1 -1
- data/crates/kobako-transport/src/abi.rs +1 -1
- data/crates/kobako-transport/src/envelope/fault.rs +2 -1
- data/crates/kobako-transport/src/envelope/preamble.rs +12 -12
- data/crates/kobako-transport/src/envelope/reply.rs +32 -14
- data/crates/kobako-transport/src/envelope/request.rs +18 -8
- data/crates/kobako-wasmtime/CHANGELOG.md +119 -0
- data/crates/kobako-wasmtime/Cargo.toml +21 -16
- data/crates/kobako-wasmtime/README.md +5 -3
- data/crates/kobako-wasmtime/src/abi.rs +66 -32
- data/crates/kobako-wasmtime/src/ambient.rs +63 -4
- data/crates/kobako-wasmtime/src/cache.rs +185 -74
- data/crates/kobako-wasmtime/src/config.rs +58 -1
- data/crates/kobako-wasmtime/src/descriptors.rs +167 -0
- data/crates/kobako-wasmtime/src/dispatch.rs +47 -29
- data/crates/kobako-wasmtime/src/driver.rs +46 -44
- data/crates/kobako-wasmtime/src/guest_mem.rs +13 -7
- data/crates/kobako-wasmtime/src/imports.rs +46 -0
- data/crates/kobako-wasmtime/src/instance_pre.rs +17 -45
- data/crates/kobako-wasmtime/src/invocation.rs +35 -46
- data/crates/kobako-wasmtime/src/io.rs +5 -202
- data/crates/kobako-wasmtime/src/lib.rs +4 -0
- data/crates/kobako-wasmtime/src/preview1/args.rs +60 -0
- data/crates/kobako-wasmtime/src/preview1/beneath.rs +188 -0
- data/crates/kobako-wasmtime/src/preview1/differential/mount.rs +609 -0
- data/crates/kobako-wasmtime/src/preview1/differential.rs +372 -0
- data/crates/kobako-wasmtime/src/preview1/errno.rs +267 -0
- data/crates/kobako-wasmtime/src/preview1/fd.rs +672 -0
- data/crates/kobako-wasmtime/src/preview1/memory.rs +205 -0
- data/crates/kobako-wasmtime/src/preview1/mount_view.rs +2499 -0
- data/crates/kobako-wasmtime/src/preview1/path.rs +421 -0
- data/crates/kobako-wasmtime/src/preview1/poll.rs +333 -0
- data/crates/kobako-wasmtime/src/preview1/sock.rs +30 -0
- data/crates/kobako-wasmtime/src/preview1.rs +461 -0
- data/crates/kobako-wasmtime/src/trap.rs +39 -19
- data/crates/kobako-wasmtime/src/wasi.rs +317 -0
- data/crates/kobako-wasmtime/tests/compile_posture.rs +43 -0
- data/crates/kobako-wasmtime/tests/guest_file.rs +1054 -0
- data/crates/kobako-wasmtime/tests/preamble_flags.rs +3 -2
- data/crates/kobako-wasmtime/tests/snippet_compile.rs +4 -3
- data/crates/kobako-wasmtime/tests/support/mod.rs +9 -13
- data/crates/kobako-wasmtime/tests/unanswered_call.rs +86 -0
- data/crates/kobako-wasmtime/tests/unsupported_call.rs +1 -0
- data/data/kobako.wasm +0 -0
- data/ext/kobako/Cargo.toml +4 -2
- data/ext/kobako/src/runtime/bridge.rs +154 -81
- data/ext/kobako/src/runtime/escape.rs +53 -0
- data/ext/kobako/src/runtime/filesystem/grants.rs +91 -0
- data/ext/kobako/src/runtime/filesystem/ruby.rs +400 -0
- data/ext/kobako/src/runtime/filesystem.rs +236 -0
- data/ext/kobako/src/runtime/gvl.rs +7 -1
- data/ext/kobako/src/runtime/pinned_value.rs +31 -0
- data/ext/kobako/src/runtime/snapshot.rs +127 -0
- data/ext/kobako/src/runtime.rs +120 -199
- data/lib/kobako/catalog/flags.rb +2 -14
- data/lib/kobako/catalog/grants.rb +30 -0
- data/lib/kobako/catalog/mount.rb +27 -0
- data/lib/kobako/catalog/services.rb +11 -0
- data/lib/kobako/catalog/snippets.rb +5 -9
- data/lib/kobako/catalog.rb +11 -0
- data/lib/kobako/codec/decoder.rb +1 -0
- data/lib/kobako/codec/ext_types.rb +1 -1
- data/lib/kobako/codec/state.rb +19 -3
- data/lib/kobako/codec/value_budget.rb +86 -0
- data/lib/kobako/codec.rb +7 -0
- data/lib/kobako/context.rb +38 -11
- data/lib/kobako/errors.rb +15 -14
- data/lib/kobako/filesystem.rb +38 -0
- data/lib/kobako/pool.rb +2 -2
- data/lib/kobako/sandbox.rb +40 -12
- data/lib/kobako/sandbox_options.rb +39 -12
- data/lib/kobako/snippet/{binary.rb → bytecode.rb} +1 -1
- data/lib/kobako/snippet.rb +1 -1
- data/lib/kobako/transport/block_failure.rb +35 -0
- data/lib/kobako/transport/dispatcher.rb +30 -26
- data/lib/kobako/transport/exposure.rb +5 -7
- data/lib/kobako/transport/reflection.rb +79 -23
- data/lib/kobako/transport/yielder.rb +8 -30
- data/lib/kobako/transport.rb +1 -0
- data/lib/kobako/version.rb +1 -1
- data/lib/kobako.rb +1 -0
- data/sig/kobako/catalog/flags.rbs +0 -4
- data/sig/kobako/catalog/grants.rbs +13 -0
- data/sig/kobako/catalog/mount.rbs +28 -0
- data/sig/kobako/catalog/services.rbs +4 -0
- data/sig/kobako/catalog/snippets.rbs +1 -1
- data/sig/kobako/catalog.rbs +1 -0
- data/sig/kobako/codec/state.rbs +7 -1
- data/sig/kobako/codec/value_budget.rbs +23 -0
- data/sig/kobako/codec.rbs +2 -0
- data/sig/kobako/context.rbs +14 -6
- data/sig/kobako/errors.rbs +4 -4
- data/sig/kobako/filesystem.rbs +88 -0
- data/sig/kobako/guest_yielder.rbs +9 -0
- data/sig/kobako/pool.rbs +1 -1
- data/sig/kobako/runtime.rbs +21 -49
- data/sig/kobako/sandbox.rbs +7 -1
- data/sig/kobako/sandbox_options.rbs +24 -2
- data/sig/kobako/snapshot.rbs +20 -0
- data/sig/kobako/snippet/bytecode.rbs +12 -0
- data/sig/kobako/transport/block_failure.rbs +13 -0
- data/sig/kobako/transport/dispatcher.rbs +3 -3
- data/sig/kobako/transport/exposure.rbs +1 -1
- data/sig/kobako/transport/reflection.rbs +14 -1
- data/sig/kobako/transport/yielder.rbs +3 -7
- data/sig/kobako/transport.rbs +2 -2
- metadata +60 -7
- data/sig/kobako/snippet/binary.rbs +0 -12
|
@@ -0,0 +1,461 @@
|
|
|
1
|
+
//! kobako's own answers to the 36 preview1 imports that read the
|
|
2
|
+
//! descriptor table: `fd_*`, `path_*`, `sock_*`, and `poll_oneoff`.
|
|
3
|
+
//!
|
|
4
|
+
//! wasmtime-wasi keeps its table private, so a descriptor kobako places
|
|
5
|
+
//! there would stay invisible to its calls. Answering every call that reads
|
|
6
|
+
//! a descriptor keeps the guest on one table, `crate::descriptors`, where
|
|
7
|
+
//! each Mount is a preopen. The other ten imports — arguments,
|
|
8
|
+
//! environment, clocks, process, scheduling, and randomness — stay
|
|
9
|
+
//! wasmtime-wasi's.
|
|
10
|
+
|
|
11
|
+
mod args;
|
|
12
|
+
mod beneath;
|
|
13
|
+
mod errno;
|
|
14
|
+
mod fd;
|
|
15
|
+
mod memory;
|
|
16
|
+
mod path;
|
|
17
|
+
mod poll;
|
|
18
|
+
mod sock;
|
|
19
|
+
|
|
20
|
+
#[cfg(test)]
|
|
21
|
+
mod differential;
|
|
22
|
+
#[cfg(test)]
|
|
23
|
+
mod mount_view;
|
|
24
|
+
|
|
25
|
+
use wasmtime::{Caller, Extern, Linker};
|
|
26
|
+
|
|
27
|
+
use crate::descriptors::Descriptors;
|
|
28
|
+
use crate::invocation::Invocation;
|
|
29
|
+
use errno::{Answer, Failure};
|
|
30
|
+
use memory::GuestMemory;
|
|
31
|
+
use path::OpenFlags;
|
|
32
|
+
|
|
33
|
+
const MODULE: &str = "wasi_snapshot_preview1";
|
|
34
|
+
|
|
35
|
+
/// Run one call against the calling instance's memory and invocation,
|
|
36
|
+
/// answering its `errno`, or the trap that ends the invocation.
|
|
37
|
+
fn answer(
|
|
38
|
+
caller: &mut Caller<'_, Invocation>,
|
|
39
|
+
call: impl FnOnce(&mut GuestMemory, &mut Invocation) -> Answer,
|
|
40
|
+
) -> wasmtime::Result<i32> {
|
|
41
|
+
let memory = caller
|
|
42
|
+
.get_export("memory")
|
|
43
|
+
.and_then(Extern::into_memory)
|
|
44
|
+
.ok_or_else(|| wasmtime::Error::msg("a preview1 call needs the guest's `memory` export"))?;
|
|
45
|
+
let (bytes, invocation) = memory.data_and_store_mut(caller);
|
|
46
|
+
let answer = call(&mut GuestMemory::new(bytes), invocation);
|
|
47
|
+
if let Some(trap) = invocation.abandonment() {
|
|
48
|
+
return Err(trap);
|
|
49
|
+
}
|
|
50
|
+
match answer {
|
|
51
|
+
Ok(()) => Ok(0),
|
|
52
|
+
Err(Failure::Errno(errno)) => Ok(errno as i32),
|
|
53
|
+
Err(Failure::Trap(trap)) => Err(trap),
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
fn table(invocation: &mut Invocation) -> &mut Descriptors {
|
|
58
|
+
invocation.wasi_mut().descriptors_mut()
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/// Define kobako's answers over wasmtime-wasi's for the same names.
|
|
62
|
+
pub(crate) fn shadow(linker: &mut Linker<Invocation>) -> wasmtime::Result<()> {
|
|
63
|
+
linker.allow_shadowing(true);
|
|
64
|
+
shadow_fd(linker)?;
|
|
65
|
+
shadow_path(linker)?;
|
|
66
|
+
shadow_poll_and_sock(linker)?;
|
|
67
|
+
linker.allow_shadowing(false);
|
|
68
|
+
Ok(())
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
fn shadow_fd(linker: &mut Linker<Invocation>) -> wasmtime::Result<()> {
|
|
72
|
+
type C<'a> = Caller<'a, Invocation>;
|
|
73
|
+
linker.func_wrap(
|
|
74
|
+
MODULE,
|
|
75
|
+
"fd_advise",
|
|
76
|
+
|mut c: C, fd: i32, offset: i64, len: i64, advice: i32| {
|
|
77
|
+
answer(&mut c, |_, inv| {
|
|
78
|
+
fd::advise(
|
|
79
|
+
table(inv),
|
|
80
|
+
fd as u32,
|
|
81
|
+
offset as u64,
|
|
82
|
+
len as u64,
|
|
83
|
+
advice as u32,
|
|
84
|
+
)
|
|
85
|
+
})
|
|
86
|
+
},
|
|
87
|
+
)?;
|
|
88
|
+
linker.func_wrap(
|
|
89
|
+
MODULE,
|
|
90
|
+
"fd_allocate",
|
|
91
|
+
|mut c: C, fd: i32, _: i64, _: i64| {
|
|
92
|
+
answer(&mut c, |_, inv| fd::allocate(table(inv), fd as u32))
|
|
93
|
+
},
|
|
94
|
+
)?;
|
|
95
|
+
linker.func_wrap(MODULE, "fd_close", |mut c: C, fd: i32| {
|
|
96
|
+
answer(&mut c, |_, inv| fd::close(table(inv), fd as u32))
|
|
97
|
+
})?;
|
|
98
|
+
// A Filesystem makes what was written durable in one step, so data
|
|
99
|
+
// and metadata sync alike.
|
|
100
|
+
for name in ["fd_datasync", "fd_sync"] {
|
|
101
|
+
linker.func_wrap(MODULE, name, |mut c: C, fd: i32| {
|
|
102
|
+
answer(&mut c, |_, inv| fd::sync(table(inv), fd as u32))
|
|
103
|
+
})?;
|
|
104
|
+
}
|
|
105
|
+
linker.func_wrap(MODULE, "fd_fdstat_get", |mut c: C, fd: i32, out: i32| {
|
|
106
|
+
answer(&mut c, |mem, inv| {
|
|
107
|
+
fd::fdstat_get(table(inv), mem, fd as u32, out as u32)
|
|
108
|
+
})
|
|
109
|
+
})?;
|
|
110
|
+
linker.func_wrap(
|
|
111
|
+
MODULE,
|
|
112
|
+
"fd_fdstat_set_flags",
|
|
113
|
+
|mut c: C, fd: i32, flags: i32| {
|
|
114
|
+
answer(&mut c, |_, inv| {
|
|
115
|
+
fd::fdstat_set_flags(table(inv), fd as u32, flags as u32)
|
|
116
|
+
})
|
|
117
|
+
},
|
|
118
|
+
)?;
|
|
119
|
+
linker.func_wrap(
|
|
120
|
+
MODULE,
|
|
121
|
+
"fd_fdstat_set_rights",
|
|
122
|
+
|mut c: C, fd: i32, base: i64, inheriting: i64| {
|
|
123
|
+
answer(&mut c, |_, inv| {
|
|
124
|
+
fd::fdstat_set_rights(table(inv), fd as u32, base as u64, inheriting as u64)
|
|
125
|
+
})
|
|
126
|
+
},
|
|
127
|
+
)?;
|
|
128
|
+
linker.func_wrap(MODULE, "fd_filestat_get", |mut c: C, fd: i32, out: i32| {
|
|
129
|
+
answer(&mut c, |mem, inv| {
|
|
130
|
+
fd::filestat_get(table(inv), mem, fd as u32, out as u32)
|
|
131
|
+
})
|
|
132
|
+
})?;
|
|
133
|
+
linker.func_wrap(
|
|
134
|
+
MODULE,
|
|
135
|
+
"fd_filestat_set_size",
|
|
136
|
+
|mut c: C, fd: i32, size: i64| {
|
|
137
|
+
answer(&mut c, |_, inv| {
|
|
138
|
+
fd::filestat_set_size(table(inv), fd as u32, size as u64)
|
|
139
|
+
})
|
|
140
|
+
},
|
|
141
|
+
)?;
|
|
142
|
+
linker.func_wrap(
|
|
143
|
+
MODULE,
|
|
144
|
+
"fd_filestat_set_times",
|
|
145
|
+
|mut c: C, fd: i32, _: i64, _: i64, fst_flags: i32| {
|
|
146
|
+
answer(&mut c, |_, inv| {
|
|
147
|
+
fd::filestat_set_times(table(inv), fd as u32, fst_flags as u32)
|
|
148
|
+
})
|
|
149
|
+
},
|
|
150
|
+
)?;
|
|
151
|
+
linker.func_wrap(
|
|
152
|
+
MODULE,
|
|
153
|
+
"fd_pread",
|
|
154
|
+
|mut c: C, fd: i32, iovs: i32, iovs_len: i32, offset: i64, nread: i32| {
|
|
155
|
+
answer(&mut c, |mem, inv| {
|
|
156
|
+
let iovs = (iovs as u32, iovs_len as u32);
|
|
157
|
+
fd::pread(
|
|
158
|
+
table(inv),
|
|
159
|
+
mem,
|
|
160
|
+
fd as u32,
|
|
161
|
+
iovs,
|
|
162
|
+
offset as u64,
|
|
163
|
+
nread as u32,
|
|
164
|
+
)
|
|
165
|
+
})
|
|
166
|
+
},
|
|
167
|
+
)?;
|
|
168
|
+
linker.func_wrap(MODULE, "fd_prestat_get", |mut c: C, fd: i32, out: i32| {
|
|
169
|
+
answer(&mut c, |mem, inv| {
|
|
170
|
+
fd::prestat_get(table(inv), mem, fd as u32, out as u32)
|
|
171
|
+
})
|
|
172
|
+
})?;
|
|
173
|
+
linker.func_wrap(
|
|
174
|
+
MODULE,
|
|
175
|
+
"fd_prestat_dir_name",
|
|
176
|
+
|mut c: C, fd: i32, path: i32, path_len: i32| {
|
|
177
|
+
answer(&mut c, |mem, inv| {
|
|
178
|
+
fd::prestat_dir_name(table(inv), mem, fd as u32, path as u32, path_len as u32)
|
|
179
|
+
})
|
|
180
|
+
},
|
|
181
|
+
)?;
|
|
182
|
+
linker.func_wrap(
|
|
183
|
+
MODULE,
|
|
184
|
+
"fd_pwrite",
|
|
185
|
+
|mut c: C, fd: i32, ciovs: i32, ciovs_len: i32, offset: i64, nwritten: i32| {
|
|
186
|
+
answer(&mut c, |mem, inv| {
|
|
187
|
+
let ciovs = (ciovs as u32, ciovs_len as u32);
|
|
188
|
+
fd::pwrite(
|
|
189
|
+
table(inv),
|
|
190
|
+
mem,
|
|
191
|
+
fd as u32,
|
|
192
|
+
ciovs,
|
|
193
|
+
offset as u64,
|
|
194
|
+
nwritten as u32,
|
|
195
|
+
)
|
|
196
|
+
})
|
|
197
|
+
},
|
|
198
|
+
)?;
|
|
199
|
+
linker.func_wrap(
|
|
200
|
+
MODULE,
|
|
201
|
+
"fd_read",
|
|
202
|
+
|mut c: C, fd: i32, iovs: i32, iovs_len: i32, nread: i32| {
|
|
203
|
+
answer(&mut c, |mem, inv| {
|
|
204
|
+
let iovs = (iovs as u32, iovs_len as u32);
|
|
205
|
+
fd::read(table(inv), mem, fd as u32, iovs, nread as u32)
|
|
206
|
+
})
|
|
207
|
+
},
|
|
208
|
+
)?;
|
|
209
|
+
linker.func_wrap(
|
|
210
|
+
MODULE,
|
|
211
|
+
"fd_readdir",
|
|
212
|
+
|mut c: C, fd: i32, buf: i32, buf_len: i32, cookie: i64, bufused: i32| {
|
|
213
|
+
answer(&mut c, |mem, inv| {
|
|
214
|
+
let buf = (buf as u32, buf_len as u32);
|
|
215
|
+
fd::readdir(
|
|
216
|
+
table(inv),
|
|
217
|
+
mem,
|
|
218
|
+
fd as u32,
|
|
219
|
+
buf,
|
|
220
|
+
cookie as u64,
|
|
221
|
+
bufused as u32,
|
|
222
|
+
)
|
|
223
|
+
})
|
|
224
|
+
},
|
|
225
|
+
)?;
|
|
226
|
+
linker.func_wrap(MODULE, "fd_renumber", |mut c: C, from: i32, to: i32| {
|
|
227
|
+
answer(&mut c, |_, inv| {
|
|
228
|
+
fd::renumber(table(inv), from as u32, to as u32)
|
|
229
|
+
})
|
|
230
|
+
})?;
|
|
231
|
+
linker.func_wrap(
|
|
232
|
+
MODULE,
|
|
233
|
+
"fd_seek",
|
|
234
|
+
|mut c: C, fd: i32, offset: i64, whence: i32, out: i32| {
|
|
235
|
+
answer(&mut c, |mem, inv| {
|
|
236
|
+
fd::seek(
|
|
237
|
+
table(inv),
|
|
238
|
+
mem,
|
|
239
|
+
fd as u32,
|
|
240
|
+
offset,
|
|
241
|
+
whence as u32,
|
|
242
|
+
out as u32,
|
|
243
|
+
)
|
|
244
|
+
})
|
|
245
|
+
},
|
|
246
|
+
)?;
|
|
247
|
+
linker.func_wrap(MODULE, "fd_tell", |mut c: C, fd: i32, out: i32| {
|
|
248
|
+
answer(&mut c, |mem, inv| {
|
|
249
|
+
fd::tell(table(inv), mem, fd as u32, out as u32)
|
|
250
|
+
})
|
|
251
|
+
})?;
|
|
252
|
+
linker.func_wrap(
|
|
253
|
+
MODULE,
|
|
254
|
+
"fd_write",
|
|
255
|
+
|mut c: C, fd: i32, ciovs: i32, ciovs_len: i32, nwritten: i32| {
|
|
256
|
+
answer(&mut c, |mem, inv| {
|
|
257
|
+
let ciovs = (ciovs as u32, ciovs_len as u32);
|
|
258
|
+
fd::write(table(inv), mem, fd as u32, ciovs, nwritten as u32)
|
|
259
|
+
})
|
|
260
|
+
},
|
|
261
|
+
)?;
|
|
262
|
+
Ok(())
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
fn shadow_path(linker: &mut Linker<Invocation>) -> wasmtime::Result<()> {
|
|
266
|
+
type C<'a> = Caller<'a, Invocation>;
|
|
267
|
+
linker.func_wrap(
|
|
268
|
+
MODULE,
|
|
269
|
+
"path_create_directory",
|
|
270
|
+
|mut c: C, fd: i32, path: i32, len: i32| {
|
|
271
|
+
answer(&mut c, |mem, inv| {
|
|
272
|
+
path::create_directory(table(inv), mem, fd as u32, (path as u32, len as u32))
|
|
273
|
+
})
|
|
274
|
+
},
|
|
275
|
+
)?;
|
|
276
|
+
linker.func_wrap(
|
|
277
|
+
MODULE,
|
|
278
|
+
"path_filestat_get",
|
|
279
|
+
|mut c: C, fd: i32, flags: i32, path: i32, len: i32, out: i32| {
|
|
280
|
+
answer(&mut c, |mem, inv| {
|
|
281
|
+
let path = (path as u32, len as u32);
|
|
282
|
+
path::filestat_get(table(inv), mem, fd as u32, flags as u32, path, out as u32)
|
|
283
|
+
})
|
|
284
|
+
},
|
|
285
|
+
)?;
|
|
286
|
+
linker.func_wrap(
|
|
287
|
+
MODULE,
|
|
288
|
+
"path_filestat_set_times",
|
|
289
|
+
|mut c: C, fd: i32, flags: i32, path: i32, len: i32, _: i64, _: i64, fst_flags: i32| {
|
|
290
|
+
answer(&mut c, |mem, inv| {
|
|
291
|
+
let path = (path as u32, len as u32);
|
|
292
|
+
path::filestat_set_times(
|
|
293
|
+
table(inv),
|
|
294
|
+
mem,
|
|
295
|
+
fd as u32,
|
|
296
|
+
flags as u32,
|
|
297
|
+
path,
|
|
298
|
+
fst_flags as u32,
|
|
299
|
+
)
|
|
300
|
+
})
|
|
301
|
+
},
|
|
302
|
+
)?;
|
|
303
|
+
linker.func_wrap(
|
|
304
|
+
MODULE,
|
|
305
|
+
"path_link",
|
|
306
|
+
|mut c: C,
|
|
307
|
+
old_fd: i32,
|
|
308
|
+
old_flags: i32,
|
|
309
|
+
old_path: i32,
|
|
310
|
+
old_len: i32,
|
|
311
|
+
new_fd: i32,
|
|
312
|
+
new_path: i32,
|
|
313
|
+
new_len: i32| {
|
|
314
|
+
answer(&mut c, |mem, inv| {
|
|
315
|
+
path::link(
|
|
316
|
+
table(inv),
|
|
317
|
+
mem,
|
|
318
|
+
old_fd as u32,
|
|
319
|
+
old_flags as u32,
|
|
320
|
+
(old_path as u32, old_len as u32),
|
|
321
|
+
new_fd as u32,
|
|
322
|
+
(new_path as u32, new_len as u32),
|
|
323
|
+
)
|
|
324
|
+
})
|
|
325
|
+
},
|
|
326
|
+
)?;
|
|
327
|
+
linker.func_wrap(
|
|
328
|
+
MODULE,
|
|
329
|
+
"path_open",
|
|
330
|
+
|mut c: C,
|
|
331
|
+
fd: i32,
|
|
332
|
+
dirflags: i32,
|
|
333
|
+
path: i32,
|
|
334
|
+
path_len: i32,
|
|
335
|
+
oflags: i32,
|
|
336
|
+
rights_base: i64,
|
|
337
|
+
rights_inheriting: i64,
|
|
338
|
+
fdflags: i32,
|
|
339
|
+
out: i32| {
|
|
340
|
+
let flags = OpenFlags {
|
|
341
|
+
dirflags: dirflags as u32,
|
|
342
|
+
oflags: oflags as u32,
|
|
343
|
+
rights_base: rights_base as u64,
|
|
344
|
+
rights_inheriting: rights_inheriting as u64,
|
|
345
|
+
fdflags: fdflags as u32,
|
|
346
|
+
};
|
|
347
|
+
answer(&mut c, |mem, inv| {
|
|
348
|
+
let path = (path as u32, path_len as u32);
|
|
349
|
+
path::open(table(inv), mem, fd as u32, path, &flags, out as u32)
|
|
350
|
+
})
|
|
351
|
+
},
|
|
352
|
+
)?;
|
|
353
|
+
linker.func_wrap(
|
|
354
|
+
MODULE,
|
|
355
|
+
"path_readlink",
|
|
356
|
+
|mut c: C, fd: i32, path: i32, len: i32, _: i32, _: i32, _: i32| {
|
|
357
|
+
answer(&mut c, |mem, inv| {
|
|
358
|
+
path::readlink(table(inv), mem, fd as u32, (path as u32, len as u32))
|
|
359
|
+
})
|
|
360
|
+
},
|
|
361
|
+
)?;
|
|
362
|
+
linker.func_wrap(
|
|
363
|
+
MODULE,
|
|
364
|
+
"path_remove_directory",
|
|
365
|
+
|mut c: C, fd: i32, path: i32, len: i32| {
|
|
366
|
+
answer(&mut c, |mem, inv| {
|
|
367
|
+
path::remove_directory(table(inv), mem, fd as u32, (path as u32, len as u32))
|
|
368
|
+
})
|
|
369
|
+
},
|
|
370
|
+
)?;
|
|
371
|
+
linker.func_wrap(
|
|
372
|
+
MODULE,
|
|
373
|
+
"path_rename",
|
|
374
|
+
|mut c: C, fd: i32, old: i32, old_len: i32, new_fd: i32, new: i32, new_len: i32| {
|
|
375
|
+
answer(&mut c, |mem, inv| {
|
|
376
|
+
path::rename(
|
|
377
|
+
table(inv),
|
|
378
|
+
mem,
|
|
379
|
+
(fd as u32, (old as u32, old_len as u32)),
|
|
380
|
+
(new_fd as u32, (new as u32, new_len as u32)),
|
|
381
|
+
)
|
|
382
|
+
})
|
|
383
|
+
},
|
|
384
|
+
)?;
|
|
385
|
+
linker.func_wrap(
|
|
386
|
+
MODULE,
|
|
387
|
+
"path_symlink",
|
|
388
|
+
|mut c: C, old: i32, old_len: i32, fd: i32, new: i32, new_len: i32| {
|
|
389
|
+
answer(&mut c, |mem, inv| {
|
|
390
|
+
path::symlink(
|
|
391
|
+
table(inv),
|
|
392
|
+
mem,
|
|
393
|
+
(old as u32, old_len as u32),
|
|
394
|
+
fd as u32,
|
|
395
|
+
(new as u32, new_len as u32),
|
|
396
|
+
)
|
|
397
|
+
})
|
|
398
|
+
},
|
|
399
|
+
)?;
|
|
400
|
+
linker.func_wrap(
|
|
401
|
+
MODULE,
|
|
402
|
+
"path_unlink_file",
|
|
403
|
+
|mut c: C, fd: i32, path: i32, len: i32| {
|
|
404
|
+
answer(&mut c, |mem, inv| {
|
|
405
|
+
path::unlink_file(table(inv), mem, fd as u32, (path as u32, len as u32))
|
|
406
|
+
})
|
|
407
|
+
},
|
|
408
|
+
)?;
|
|
409
|
+
Ok(())
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
fn shadow_poll_and_sock(linker: &mut Linker<Invocation>) -> wasmtime::Result<()> {
|
|
413
|
+
type C<'a> = Caller<'a, Invocation>;
|
|
414
|
+
linker.func_wrap(
|
|
415
|
+
MODULE,
|
|
416
|
+
"poll_oneoff",
|
|
417
|
+
|mut c: C, subs: i32, events: i32, count: i32, nevents: i32| {
|
|
418
|
+
answer(&mut c, |mem, inv| {
|
|
419
|
+
poll::poll_oneoff(
|
|
420
|
+
inv,
|
|
421
|
+
mem,
|
|
422
|
+
subs as u32,
|
|
423
|
+
events as u32,
|
|
424
|
+
count as u32,
|
|
425
|
+
nevents as u32,
|
|
426
|
+
)
|
|
427
|
+
})
|
|
428
|
+
},
|
|
429
|
+
)?;
|
|
430
|
+
linker.func_wrap(
|
|
431
|
+
MODULE,
|
|
432
|
+
"sock_accept",
|
|
433
|
+
|mut c: C, fd: i32, flags: i32, _: i32| {
|
|
434
|
+
answer(&mut c, |_, inv| {
|
|
435
|
+
sock::accept(table(inv), fd as u32, flags as u32)
|
|
436
|
+
})
|
|
437
|
+
},
|
|
438
|
+
)?;
|
|
439
|
+
linker.func_wrap(
|
|
440
|
+
MODULE,
|
|
441
|
+
"sock_recv",
|
|
442
|
+
|mut c: C, fd: i32, _: i32, _: i32, ri_flags: i32, _: i32, _: i32| {
|
|
443
|
+
answer(&mut c, |_, inv| {
|
|
444
|
+
sock::recv(table(inv), fd as u32, ri_flags as u32)
|
|
445
|
+
})
|
|
446
|
+
},
|
|
447
|
+
)?;
|
|
448
|
+
linker.func_wrap(
|
|
449
|
+
MODULE,
|
|
450
|
+
"sock_send",
|
|
451
|
+
|mut c: C, fd: i32, _: i32, _: i32, _: i32, _: i32| {
|
|
452
|
+
answer(&mut c, |_, inv| sock::send(table(inv), fd as u32))
|
|
453
|
+
},
|
|
454
|
+
)?;
|
|
455
|
+
linker.func_wrap(MODULE, "sock_shutdown", |mut c: C, fd: i32, how: i32| {
|
|
456
|
+
answer(&mut c, |_, inv| {
|
|
457
|
+
sock::shutdown(table(inv), fd as u32, how as u32)
|
|
458
|
+
})
|
|
459
|
+
})?;
|
|
460
|
+
Ok(())
|
|
461
|
+
}
|
|
@@ -7,9 +7,9 @@
|
|
|
7
7
|
//! pure function over the error's downcast chain so it can be exercised
|
|
8
8
|
//! from `cargo test` without any frontend.
|
|
9
9
|
|
|
10
|
-
use std::time::Instant;
|
|
10
|
+
use std::time::{Duration, Instant};
|
|
11
11
|
|
|
12
|
-
use wasmtime::{StoreContextMut, UpdateDeadline};
|
|
12
|
+
use wasmtime::{Store, StoreContextMut, UpdateDeadline};
|
|
13
13
|
|
|
14
14
|
use crate::invocation::Invocation;
|
|
15
15
|
use crate::limiter::MemoryLimitTrap;
|
|
@@ -53,13 +53,33 @@ pub(crate) fn epoch_deadline_callback(
|
|
|
53
53
|
/// The message leaves out the ABI export symbol, so the Sandbox layer can
|
|
54
54
|
/// attach the caller's verb instead. A cap trap carries its own message,
|
|
55
55
|
/// since wasmtime's backtrace framing is noise there.
|
|
56
|
-
pub(crate) fn
|
|
56
|
+
pub(crate) fn to_trap(err: wasmtime::Error) -> Trap {
|
|
57
|
+
cap_trap(&err).unwrap_or_else(|| Trap::Other(other_trap_message(&err)))
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/// Arm a Store's wall-clock deadline `limit` from now, or none. Epoch
|
|
61
|
+
/// interruption is on engine-wide and a fresh Store's deadline has already
|
|
62
|
+
/// elapsed, so an unbounded Store names one it cannot reach.
|
|
63
|
+
pub(crate) fn arm_deadline(store: &mut Store<Invocation>, limit: Option<Duration>) {
|
|
64
|
+
store.epoch_deadline_callback(epoch_deadline_callback);
|
|
65
|
+
store
|
|
66
|
+
.data_mut()
|
|
67
|
+
.set_deadline(limit.map(|limit| Instant::now() + limit));
|
|
68
|
+
store.set_epoch_deadline(if limit.is_some() {
|
|
69
|
+
1
|
|
70
|
+
} else {
|
|
71
|
+
NO_TIMEOUT_EPOCH_DELTA
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/// The cap trap `err` carries, if a cap fired: a setup step that fails
|
|
76
|
+
/// for any other reason words its own message instead.
|
|
77
|
+
pub(crate) fn cap_trap(err: &wasmtime::Error) -> Option<Trap> {
|
|
57
78
|
if let Some(t) = err.downcast_ref::<TimeoutTrap>() {
|
|
58
|
-
Trap::Timeout(t.to_string())
|
|
59
|
-
} else if let Some(t) = err.downcast_ref::<MemoryLimitTrap>() {
|
|
60
|
-
Trap::MemoryLimit(t.to_string())
|
|
79
|
+
Some(Trap::Timeout(t.to_string()))
|
|
61
80
|
} else {
|
|
62
|
-
|
|
81
|
+
err.downcast_ref::<MemoryLimitTrap>()
|
|
82
|
+
.map(|t| Trap::MemoryLimit(t.to_string()))
|
|
63
83
|
}
|
|
64
84
|
}
|
|
65
85
|
|
|
@@ -76,17 +96,17 @@ fn other_trap_message(err: &wasmtime::Error) -> String {
|
|
|
76
96
|
}
|
|
77
97
|
}
|
|
78
98
|
|
|
79
|
-
/// The template is built before any invocation, so
|
|
80
|
-
/// the memory cap is not yet armed and the probe
|
|
81
|
-
///
|
|
99
|
+
/// The template is built before any invocation, so no invocation cap can
|
|
100
|
+
/// fire: the memory cap is not yet armed, and the probe's own setup
|
|
101
|
+
/// deadline is told apart where it fires. Every failure here is a setup
|
|
102
|
+
/// fault, not a trap.
|
|
82
103
|
pub(crate) fn instantiate_err(err: wasmtime::Error) -> SetupError {
|
|
83
104
|
SetupError::Dead(format!("instantiate: {err}"))
|
|
84
105
|
}
|
|
85
106
|
|
|
86
107
|
#[cfg(test)]
|
|
87
108
|
mod tests {
|
|
88
|
-
use super::{other_trap_message,
|
|
89
|
-
use crate::invocation::Invocation;
|
|
109
|
+
use super::{other_trap_message, to_trap, TimeoutTrap, NO_TIMEOUT_EPOCH_DELTA};
|
|
90
110
|
use crate::limiter::MemoryLimitTrap;
|
|
91
111
|
use kobako_runtime::error::Trap;
|
|
92
112
|
|
|
@@ -102,32 +122,32 @@ mod tests {
|
|
|
102
122
|
fn no_timeout_delta_survives_a_ticked_engine_epoch() {
|
|
103
123
|
let engine = crate::cache::shared_engine().expect("shared engine must be constructible");
|
|
104
124
|
engine.increment_epoch();
|
|
105
|
-
let mut store = wasmtime::Store::new(engine,
|
|
125
|
+
let mut store = wasmtime::Store::new(engine, ());
|
|
106
126
|
store.set_epoch_deadline(NO_TIMEOUT_EPOCH_DELTA);
|
|
107
127
|
}
|
|
108
128
|
|
|
109
129
|
// @behavior OC-032
|
|
110
130
|
#[test]
|
|
111
|
-
fn
|
|
131
|
+
fn to_trap_routes_timeout_trap_to_timeout() {
|
|
112
132
|
let err = wasmtime::Error::new(TimeoutTrap);
|
|
113
133
|
let expected = TimeoutTrap.to_string();
|
|
114
|
-
assert!(matches!(
|
|
134
|
+
assert!(matches!(to_trap(err), Trap::Timeout(msg) if msg == expected));
|
|
115
135
|
}
|
|
116
136
|
|
|
117
137
|
// @behavior OC-033
|
|
118
138
|
#[test]
|
|
119
|
-
fn
|
|
139
|
+
fn to_trap_routes_memory_limit_trap_to_memory_limit() {
|
|
120
140
|
let trap = MemoryLimitTrap::new(1 << 20, 1 << 19);
|
|
121
141
|
let expected = trap.to_string();
|
|
122
142
|
let err = wasmtime::Error::new(trap);
|
|
123
|
-
assert!(matches!(
|
|
143
|
+
assert!(matches!(to_trap(err), Trap::MemoryLimit(msg) if msg == expected));
|
|
124
144
|
}
|
|
125
145
|
|
|
126
146
|
// @behavior OC-028
|
|
127
147
|
#[test]
|
|
128
|
-
fn
|
|
148
|
+
fn to_trap_falls_back_to_other_for_unknown_errors() {
|
|
129
149
|
let err = wasmtime::Error::msg("some other wasmtime fault");
|
|
130
|
-
assert!(matches!(
|
|
150
|
+
assert!(matches!(to_trap(err), Trap::Other(_)));
|
|
131
151
|
}
|
|
132
152
|
|
|
133
153
|
// A guest hard trap reaches the host as a wasmtime error whose Display is
|