kobako 0.3.0 → 0.5.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 -0
- data/CHANGELOG.md +29 -0
- data/Cargo.lock +1 -1
- data/README.md +85 -6
- data/data/kobako.wasm +0 -0
- data/ext/kobako/Cargo.toml +1 -1
- data/ext/kobako/src/lib.rs +4 -2
- data/ext/kobako/src/{wasm → runtime}/cache.rs +22 -18
- data/ext/kobako/src/runtime/capture.rs +91 -0
- data/ext/kobako/src/runtime/config.rs +26 -0
- data/ext/kobako/src/runtime/dispatch.rs +211 -0
- data/ext/kobako/src/runtime/exports.rs +51 -0
- data/ext/kobako/src/runtime/guest_mem.rs +228 -0
- data/ext/kobako/src/{wasm/host_state.rs → runtime/invocation.rs} +195 -81
- data/ext/kobako/src/runtime/trap.rs +134 -0
- data/ext/kobako/src/runtime.rs +782 -0
- data/ext/kobako/src/snapshot.rs +110 -0
- data/lib/kobako/capture.rb +11 -16
- data/lib/kobako/catalog/handles.rb +107 -0
- data/lib/kobako/catalog/namespaces.rb +99 -0
- data/lib/kobako/{snippet/table.rb → catalog/snippets.rb} +37 -62
- data/lib/kobako/catalog.rb +18 -0
- data/lib/kobako/codec/decoder.rb +13 -7
- data/lib/kobako/codec/factory.rb +21 -18
- data/lib/kobako/codec/utils.rb +118 -29
- data/lib/kobako/codec.rb +6 -3
- data/lib/kobako/errors.rb +45 -28
- data/lib/kobako/fault.rb +40 -0
- data/lib/kobako/handle.rb +60 -0
- data/lib/kobako/namespace.rb +67 -0
- data/lib/kobako/outcome.rb +55 -29
- data/lib/kobako/runtime.rb +30 -0
- data/lib/kobako/sandbox.rb +131 -67
- data/lib/kobako/sandbox_options.rb +6 -9
- data/lib/kobako/snapshot.rb +40 -0
- data/lib/kobako/snippet/binary.rb +6 -7
- data/lib/kobako/snippet/source.rb +8 -8
- data/lib/kobako/snippet.rb +7 -9
- data/lib/kobako/transport/dispatcher.rb +195 -0
- data/lib/kobako/transport/error.rb +24 -0
- data/lib/kobako/transport/request.rb +78 -0
- data/lib/kobako/transport/response.rb +69 -0
- data/lib/kobako/transport/run.rb +141 -0
- data/lib/kobako/transport/yield.rb +91 -0
- data/lib/kobako/transport/yielder.rb +89 -0
- data/lib/kobako/transport.rb +24 -0
- data/lib/kobako/usage.rb +41 -0
- data/lib/kobako/version.rb +1 -1
- data/lib/kobako.rb +4 -3
- data/release-please-config.json +24 -0
- data/sig/kobako/capture.rbs +0 -2
- data/sig/kobako/{rpc/handle_table.rbs → catalog/handles.rbs} +3 -9
- data/sig/kobako/catalog/namespaces.rbs +17 -0
- data/sig/kobako/{snippet/table.rbs → catalog/snippets.rbs} +2 -11
- data/sig/kobako/{rpc.rbs → catalog.rbs} +1 -1
- data/sig/kobako/codec/decoder.rbs +2 -1
- data/sig/kobako/codec/factory.rbs +3 -3
- data/sig/kobako/codec/utils.rbs +11 -1
- data/sig/kobako/errors.rbs +7 -7
- data/sig/kobako/fault.rbs +19 -0
- data/sig/kobako/handle.rbs +18 -0
- data/sig/kobako/namespace.rbs +19 -0
- data/sig/kobako/outcome.rbs +2 -2
- data/sig/kobako/runtime.rbs +23 -0
- data/sig/kobako/sandbox.rbs +10 -7
- data/sig/kobako/snapshot.rbs +15 -0
- data/sig/kobako/transport/dispatcher.rbs +34 -0
- data/sig/kobako/transport/error.rbs +6 -0
- data/sig/kobako/transport/request.rbs +32 -0
- data/sig/kobako/transport/response.rbs +30 -0
- data/sig/kobako/transport/run.rbs +27 -0
- data/sig/kobako/transport/yield.rbs +34 -0
- data/sig/kobako/transport/yielder.rbs +21 -0
- data/sig/kobako/transport.rbs +4 -0
- data/sig/kobako/usage.rbs +11 -0
- metadata +52 -30
- data/ext/kobako/src/wasm/dispatch.rs +0 -161
- data/ext/kobako/src/wasm/instance.rs +0 -771
- data/ext/kobako/src/wasm.rs +0 -125
- data/lib/kobako/invocation.rb +0 -112
- data/lib/kobako/rpc/dispatcher.rb +0 -169
- data/lib/kobako/rpc/envelope.rb +0 -118
- data/lib/kobako/rpc/fault.rb +0 -41
- data/lib/kobako/rpc/handle.rb +0 -39
- data/lib/kobako/rpc/handle_table.rb +0 -107
- data/lib/kobako/rpc/namespace.rb +0 -74
- data/lib/kobako/rpc/server.rb +0 -158
- data/lib/kobako/rpc.rb +0 -11
- data/lib/kobako/wasm.rb +0 -25
- data/sig/kobako/invocation.rbs +0 -23
- data/sig/kobako/rpc/dispatcher.rbs +0 -33
- data/sig/kobako/rpc/envelope.rbs +0 -51
- data/sig/kobako/rpc/fault.rbs +0 -20
- data/sig/kobako/rpc/handle.rbs +0 -19
- data/sig/kobako/rpc/namespace.rbs +0 -24
- data/sig/kobako/rpc/server.rbs +0 -37
- data/sig/kobako/wasm.rbs +0 -39
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
module Kobako
|
|
2
|
+
module Transport
|
|
3
|
+
TAG_OK: Integer
|
|
4
|
+
TAG_BREAK: Integer
|
|
5
|
+
TAG_RESERVED: Integer
|
|
6
|
+
TAG_ERROR: Integer
|
|
7
|
+
LIVE_TAGS: Array[Integer]
|
|
8
|
+
|
|
9
|
+
class Yield
|
|
10
|
+
attr_reader tag: Integer
|
|
11
|
+
attr_reader value: untyped
|
|
12
|
+
|
|
13
|
+
def self.decode: (String bytes) -> Yield
|
|
14
|
+
|
|
15
|
+
def self.reject_dead_tag!: (Integer tag) -> void
|
|
16
|
+
|
|
17
|
+
def initialize: (tag: Integer, value: untyped) -> void
|
|
18
|
+
|
|
19
|
+
def with: (?tag: Integer, ?value: untyped) -> Yield
|
|
20
|
+
|
|
21
|
+
def ok?: () -> bool
|
|
22
|
+
|
|
23
|
+
def break?: () -> bool
|
|
24
|
+
|
|
25
|
+
def error?: () -> bool
|
|
26
|
+
|
|
27
|
+
def encode: () -> String
|
|
28
|
+
|
|
29
|
+
def ==: (untyped other) -> bool
|
|
30
|
+
|
|
31
|
+
def hash: () -> Integer
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
module Kobako
|
|
2
|
+
module Transport
|
|
3
|
+
class Yielder
|
|
4
|
+
@yield_to_guest: ^(String) -> String
|
|
5
|
+
@break_tag: Symbol
|
|
6
|
+
@active: bool
|
|
7
|
+
|
|
8
|
+
def initialize: (^(String) -> String yield_to_guest, Symbol break_tag) -> void
|
|
9
|
+
|
|
10
|
+
def yield: (*untyped args) -> untyped
|
|
11
|
+
|
|
12
|
+
def to_proc: () -> Proc
|
|
13
|
+
|
|
14
|
+
def invalidate!: () -> void
|
|
15
|
+
|
|
16
|
+
private
|
|
17
|
+
|
|
18
|
+
def yield_failure: (untyped payload, default: String) -> RuntimeError
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: kobako
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.5.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Aotokitsuruya
|
|
@@ -29,14 +29,14 @@ dependencies:
|
|
|
29
29
|
requirements:
|
|
30
30
|
- - "~>"
|
|
31
31
|
- !ruby/object:Gem::Version
|
|
32
|
-
version: 0.9.
|
|
32
|
+
version: 0.9.128
|
|
33
33
|
type: :runtime
|
|
34
34
|
prerelease: false
|
|
35
35
|
version_requirements: !ruby/object:Gem::Requirement
|
|
36
36
|
requirements:
|
|
37
37
|
- - "~>"
|
|
38
38
|
- !ruby/object:Gem::Version
|
|
39
|
-
version: 0.9.
|
|
39
|
+
version: 0.9.128
|
|
40
40
|
description: kobako provides an in-process Wasm sandbox (wasmtime + mruby) with a
|
|
41
41
|
MessagePack-based host/guest RPC, allowing Ruby applications to execute untrusted
|
|
42
42
|
mruby scripts under capability-based Service injection.
|
|
@@ -47,6 +47,8 @@ extensions:
|
|
|
47
47
|
- ext/kobako/extconf.rb
|
|
48
48
|
extra_rdoc_files: []
|
|
49
49
|
files:
|
|
50
|
+
- ".release-please-manifest.json"
|
|
51
|
+
- CHANGELOG.md
|
|
50
52
|
- Cargo.lock
|
|
51
53
|
- Cargo.toml
|
|
52
54
|
- LICENSE
|
|
@@ -55,13 +57,22 @@ files:
|
|
|
55
57
|
- ext/kobako/Cargo.toml
|
|
56
58
|
- ext/kobako/extconf.rb
|
|
57
59
|
- ext/kobako/src/lib.rs
|
|
58
|
-
- ext/kobako/src/
|
|
59
|
-
- ext/kobako/src/
|
|
60
|
-
- ext/kobako/src/
|
|
61
|
-
- ext/kobako/src/
|
|
62
|
-
- ext/kobako/src/
|
|
60
|
+
- ext/kobako/src/runtime.rs
|
|
61
|
+
- ext/kobako/src/runtime/cache.rs
|
|
62
|
+
- ext/kobako/src/runtime/capture.rs
|
|
63
|
+
- ext/kobako/src/runtime/config.rs
|
|
64
|
+
- ext/kobako/src/runtime/dispatch.rs
|
|
65
|
+
- ext/kobako/src/runtime/exports.rs
|
|
66
|
+
- ext/kobako/src/runtime/guest_mem.rs
|
|
67
|
+
- ext/kobako/src/runtime/invocation.rs
|
|
68
|
+
- ext/kobako/src/runtime/trap.rs
|
|
69
|
+
- ext/kobako/src/snapshot.rs
|
|
63
70
|
- lib/kobako.rb
|
|
64
71
|
- lib/kobako/capture.rb
|
|
72
|
+
- lib/kobako/catalog.rb
|
|
73
|
+
- lib/kobako/catalog/handles.rb
|
|
74
|
+
- lib/kobako/catalog/namespaces.rb
|
|
75
|
+
- lib/kobako/catalog/snippets.rb
|
|
65
76
|
- lib/kobako/codec.rb
|
|
66
77
|
- lib/kobako/codec/decoder.rb
|
|
67
78
|
- lib/kobako/codec/encoder.rb
|
|
@@ -69,51 +80,62 @@ files:
|
|
|
69
80
|
- lib/kobako/codec/factory.rb
|
|
70
81
|
- lib/kobako/codec/utils.rb
|
|
71
82
|
- lib/kobako/errors.rb
|
|
72
|
-
- lib/kobako/
|
|
83
|
+
- lib/kobako/fault.rb
|
|
84
|
+
- lib/kobako/handle.rb
|
|
85
|
+
- lib/kobako/namespace.rb
|
|
73
86
|
- lib/kobako/outcome.rb
|
|
74
87
|
- lib/kobako/outcome/panic.rb
|
|
75
|
-
- lib/kobako/
|
|
76
|
-
- lib/kobako/rpc/dispatcher.rb
|
|
77
|
-
- lib/kobako/rpc/envelope.rb
|
|
78
|
-
- lib/kobako/rpc/fault.rb
|
|
79
|
-
- lib/kobako/rpc/handle.rb
|
|
80
|
-
- lib/kobako/rpc/handle_table.rb
|
|
81
|
-
- lib/kobako/rpc/namespace.rb
|
|
82
|
-
- lib/kobako/rpc/server.rb
|
|
88
|
+
- lib/kobako/runtime.rb
|
|
83
89
|
- lib/kobako/sandbox.rb
|
|
84
90
|
- lib/kobako/sandbox_options.rb
|
|
91
|
+
- lib/kobako/snapshot.rb
|
|
85
92
|
- lib/kobako/snippet.rb
|
|
86
93
|
- lib/kobako/snippet/binary.rb
|
|
87
94
|
- lib/kobako/snippet/source.rb
|
|
88
|
-
- lib/kobako/
|
|
95
|
+
- lib/kobako/transport.rb
|
|
96
|
+
- lib/kobako/transport/dispatcher.rb
|
|
97
|
+
- lib/kobako/transport/error.rb
|
|
98
|
+
- lib/kobako/transport/request.rb
|
|
99
|
+
- lib/kobako/transport/response.rb
|
|
100
|
+
- lib/kobako/transport/run.rb
|
|
101
|
+
- lib/kobako/transport/yield.rb
|
|
102
|
+
- lib/kobako/transport/yielder.rb
|
|
103
|
+
- lib/kobako/usage.rb
|
|
89
104
|
- lib/kobako/version.rb
|
|
90
|
-
-
|
|
105
|
+
- release-please-config.json
|
|
91
106
|
- sig/kobako.rbs
|
|
92
107
|
- sig/kobako/capture.rbs
|
|
108
|
+
- sig/kobako/catalog.rbs
|
|
109
|
+
- sig/kobako/catalog/handles.rbs
|
|
110
|
+
- sig/kobako/catalog/namespaces.rbs
|
|
111
|
+
- sig/kobako/catalog/snippets.rbs
|
|
93
112
|
- sig/kobako/codec/decoder.rbs
|
|
94
113
|
- sig/kobako/codec/encoder.rbs
|
|
95
114
|
- sig/kobako/codec/error.rbs
|
|
96
115
|
- sig/kobako/codec/factory.rbs
|
|
97
116
|
- sig/kobako/codec/utils.rbs
|
|
98
117
|
- sig/kobako/errors.rbs
|
|
99
|
-
- sig/kobako/
|
|
118
|
+
- sig/kobako/fault.rbs
|
|
119
|
+
- sig/kobako/handle.rbs
|
|
120
|
+
- sig/kobako/namespace.rbs
|
|
100
121
|
- sig/kobako/outcome.rbs
|
|
101
122
|
- sig/kobako/outcome/panic.rbs
|
|
102
|
-
- sig/kobako/
|
|
103
|
-
- sig/kobako/rpc/dispatcher.rbs
|
|
104
|
-
- sig/kobako/rpc/envelope.rbs
|
|
105
|
-
- sig/kobako/rpc/fault.rbs
|
|
106
|
-
- sig/kobako/rpc/handle.rbs
|
|
107
|
-
- sig/kobako/rpc/handle_table.rbs
|
|
108
|
-
- sig/kobako/rpc/namespace.rbs
|
|
109
|
-
- sig/kobako/rpc/server.rbs
|
|
123
|
+
- sig/kobako/runtime.rbs
|
|
110
124
|
- sig/kobako/sandbox.rbs
|
|
111
125
|
- sig/kobako/sandbox_options.rbs
|
|
126
|
+
- sig/kobako/snapshot.rbs
|
|
112
127
|
- sig/kobako/snippet.rbs
|
|
113
128
|
- sig/kobako/snippet/binary.rbs
|
|
114
129
|
- sig/kobako/snippet/source.rbs
|
|
115
|
-
- sig/kobako/
|
|
116
|
-
- sig/kobako/
|
|
130
|
+
- sig/kobako/transport.rbs
|
|
131
|
+
- sig/kobako/transport/dispatcher.rbs
|
|
132
|
+
- sig/kobako/transport/error.rbs
|
|
133
|
+
- sig/kobako/transport/request.rbs
|
|
134
|
+
- sig/kobako/transport/response.rbs
|
|
135
|
+
- sig/kobako/transport/run.rbs
|
|
136
|
+
- sig/kobako/transport/yield.rbs
|
|
137
|
+
- sig/kobako/transport/yielder.rbs
|
|
138
|
+
- sig/kobako/usage.rbs
|
|
117
139
|
homepage: https://github.com/elct9620/kobako
|
|
118
140
|
licenses:
|
|
119
141
|
- Apache-2.0
|
|
@@ -1,161 +0,0 @@
|
|
|
1
|
-
//! Host-side dispatch for the `__kobako_dispatch` import.
|
|
2
|
-
//!
|
|
3
|
-
//! When the guest invokes the wasm import declared in
|
|
4
|
-
//! `wasm/kobako-wasm/src/abi.rs`, wasmtime calls back into the host
|
|
5
|
-
//! through the closure built in [`super::instance::Instance::build`].
|
|
6
|
-
//! That closure delegates here. The dispatcher (docs/behavior.md B-12 / B-13):
|
|
7
|
-
//!
|
|
8
|
-
//! 1. Reads the Request bytes from guest linear memory.
|
|
9
|
-
//! 2. Hands them to the Ruby-side `Kobako::RPC::Server` and recovers
|
|
10
|
-
//! Response bytes.
|
|
11
|
-
//! 3. Allocates a guest buffer via `__kobako_alloc(len)` invoked
|
|
12
|
-
//! through `Caller::get_export`.
|
|
13
|
-
//! 4. Writes the Response bytes into the guest buffer.
|
|
14
|
-
//! 5. Returns packed `(ptr<<32)|len` for the guest to decode.
|
|
15
|
-
//!
|
|
16
|
-
//! Returns 0 on any step failure. `Kobako::Sandbox` always installs a
|
|
17
|
-
//! Server before invoking the guest, so reaching the dispatcher with
|
|
18
|
-
//! no Server bound is itself a wire-layer fault; the guest maps a 0
|
|
19
|
-
//! return to a trap. Failures during normal dispatch surface as
|
|
20
|
-
//! Response.err envelopes from the Server itself — they never reach
|
|
21
|
-
//! this 0-return path.
|
|
22
|
-
//!
|
|
23
|
-
//! ## Why this module writes to `stderr`
|
|
24
|
-
//!
|
|
25
|
-
//! This file is the one place in `ext/` that deliberately prints
|
|
26
|
-
//! through `eprintln!`. The host normally surfaces faults by
|
|
27
|
-
//! raising a `MagnusError` back into Ruby; the dispatcher contract
|
|
28
|
-
//! is the exception — it must return a packed `i64` to the guest
|
|
29
|
-
//! and cannot raise, so a 0 return is the only signal the wasm side
|
|
30
|
-
//! receives. The guest collapses every 0 into the same trap, so the
|
|
31
|
-
//! Ruby host has no way to attribute the failure to a specific
|
|
32
|
-
//! step (missing `memory` export vs. no Server bound vs. Server
|
|
33
|
-
//! raised vs. `__kobako_alloc` returned 0 vs. `memory.write`
|
|
34
|
-
//! rejected).
|
|
35
|
-
//!
|
|
36
|
-
//! [`handle`] writes a single `[kobako-dispatch] <reason>` line to
|
|
37
|
-
//! `stderr` on each failure path so operators have a breadcrumb to
|
|
38
|
-
//! correlate the trap with the actual cause. The line is emitted in
|
|
39
|
-
//! both debug and release builds on purpose: dispatcher failures
|
|
40
|
-
//! are wire-layer faults rather than expected error paths
|
|
41
|
-
//! (`Kobako::Sandbox` always installs a Server, the Server is
|
|
42
|
-
//! contracted never to raise, etc.), so the "release-build noise"
|
|
43
|
-
//! cost is bounded — under normal operation the line is never
|
|
44
|
-
//! written. Operators that need to silence the channel can redirect
|
|
45
|
-
//! the host process's stderr, but the kobako convention is "ext
|
|
46
|
-
//! never logs" plus this single, named exception.
|
|
47
|
-
|
|
48
|
-
use magnus::value::{Opaque, ReprValue};
|
|
49
|
-
use magnus::{Error as MagnusError, RString, Ruby, Value};
|
|
50
|
-
use wasmtime::{Caller, Extern};
|
|
51
|
-
|
|
52
|
-
use super::host_state::HostState;
|
|
53
|
-
|
|
54
|
-
/// Drive a single `__kobako_dispatch` invocation end-to-end. Entry point
|
|
55
|
-
/// from the wasmtime closure built in [`super::instance::Instance::build`].
|
|
56
|
-
///
|
|
57
|
-
/// Returns the packed `(ptr<<32)|len` u64 on success, 0 on any
|
|
58
|
-
/// wire-layer fault. Failure paths log a `[kobako-dispatch]` line to
|
|
59
|
-
/// `stderr` so operators have a breadcrumb when the guest sees a 0
|
|
60
|
-
/// return and traps; before this every failure was silent. The Server
|
|
61
|
-
/// itself is contracted never to raise (it folds Service exceptions
|
|
62
|
-
/// into Response.err envelopes), so reaching the failure path is
|
|
63
|
-
/// always a wiring bug or wire-layer fault rather than an expected
|
|
64
|
-
/// path.
|
|
65
|
-
pub(crate) fn handle(caller: &mut Caller<'_, HostState>, req_ptr: i32, req_len: i32) -> i64 {
|
|
66
|
-
match try_handle(caller, req_ptr, req_len) {
|
|
67
|
-
Ok(packed) => packed,
|
|
68
|
-
Err(reason) => {
|
|
69
|
-
eprintln!("[kobako-dispatch] {}", reason);
|
|
70
|
-
0
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
/// Result-returning core of [`handle`]. Pulled out so each early
|
|
76
|
-
/// failure path carries a diagnostic string instead of an opaque 0.
|
|
77
|
-
fn try_handle(
|
|
78
|
-
caller: &mut Caller<'_, HostState>,
|
|
79
|
-
req_ptr: i32,
|
|
80
|
-
req_len: i32,
|
|
81
|
-
) -> Result<i64, &'static str> {
|
|
82
|
-
let req_bytes = read_caller_memory(caller, req_ptr, req_len)
|
|
83
|
-
.ok_or("guest 'memory' export missing or request slice out of bounds")?;
|
|
84
|
-
|
|
85
|
-
// `Kobako::Sandbox` always installs a Server before invoking the
|
|
86
|
-
// guest, so reaching this branch indicates a misuse rather than a
|
|
87
|
-
// normal control path.
|
|
88
|
-
let server = caller
|
|
89
|
-
.data()
|
|
90
|
-
.server()
|
|
91
|
-
.ok_or("no Ruby Server bound — Sandbox#run must precede __kobako_dispatch")?;
|
|
92
|
-
|
|
93
|
-
let resp_bytes = invoke_server(server, &req_bytes).map_err(|_| {
|
|
94
|
-
"Ruby Server#dispatch raised — contract is to fold faults into Response.err"
|
|
95
|
-
})?;
|
|
96
|
-
|
|
97
|
-
write_response(caller, &resp_bytes)
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
/// Call the Ruby Server's `#dispatch(request_bytes)` method and return
|
|
101
|
-
/// the encoded Response bytes. Errors here mean the Server itself
|
|
102
|
-
/// failed (it is contracted never to raise — see
|
|
103
|
-
/// `Kobako::RPC::Server#dispatch`), which we treat as a wire-layer fault.
|
|
104
|
-
fn invoke_server(server: Opaque<Value>, req_bytes: &[u8]) -> Result<Vec<u8>, MagnusError> {
|
|
105
|
-
// The wasmtime callback runs on the same Ruby thread that called the
|
|
106
|
-
// active Sandbox invocation (#eval or #run) — the invariant SPEC
|
|
107
|
-
// Implementation Standards Architecture pins for the host gem — so
|
|
108
|
-
// `Ruby::get()` is always available here. Panicking with `expect`
|
|
109
|
-
// localises the violation rather than letting a nonsense error
|
|
110
|
-
// propagate.
|
|
111
|
-
let ruby = Ruby::get().expect("Ruby handle unavailable in __kobako_dispatch");
|
|
112
|
-
let server_value: Value = ruby.get_inner(server);
|
|
113
|
-
let req_str = ruby.str_from_slice(req_bytes);
|
|
114
|
-
let resp: RString = server_value.funcall("dispatch", (req_str,))?;
|
|
115
|
-
Ok(super::rstring_to_vec(resp))
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
/// Allocate a guest-side buffer through `__kobako_alloc` and copy the
|
|
119
|
-
/// response bytes into it. Returns the packed `(ptr<<32)|len` u64.
|
|
120
|
-
/// Each failure path carries a `&'static str` reason so the dispatcher
|
|
121
|
-
/// wrapper can surface a useful diagnostic rather than a silent 0.
|
|
122
|
-
fn write_response(caller: &mut Caller<'_, HostState>, bytes: &[u8]) -> Result<i64, &'static str> {
|
|
123
|
-
let alloc = match caller.get_export("__kobako_alloc") {
|
|
124
|
-
Some(Extern::Func(f)) => f
|
|
125
|
-
.typed::<i32, i32>(&*caller)
|
|
126
|
-
.map_err(|_| "guest '__kobako_alloc' export has wrong signature")?,
|
|
127
|
-
_ => return Err("guest '__kobako_alloc' export missing"),
|
|
128
|
-
};
|
|
129
|
-
let len_i32 = i32::try_from(bytes.len()).map_err(|_| "response exceeds i32::MAX bytes")?;
|
|
130
|
-
let ptr = alloc
|
|
131
|
-
.call(&mut *caller, len_i32)
|
|
132
|
-
.map_err(|_| "__kobako_alloc trapped")?;
|
|
133
|
-
if ptr == 0 {
|
|
134
|
-
return Err("__kobako_alloc returned 0 (out of memory)");
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
let mem = match caller.get_export("memory") {
|
|
138
|
-
Some(Extern::Memory(m)) => m,
|
|
139
|
-
_ => return Err("guest 'memory' export missing"),
|
|
140
|
-
};
|
|
141
|
-
mem.write(&mut *caller, ptr as usize, bytes)
|
|
142
|
-
.map_err(|_| "memory.write rejected response buffer range")?;
|
|
143
|
-
|
|
144
|
-
let ptr_u32 = ptr as u32;
|
|
145
|
-
let len_u32 = bytes.len() as u32;
|
|
146
|
-
Ok(((ptr_u32 as i64) << 32) | (len_u32 as i64))
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
/// Copy `[ptr, ptr+len)` out of the guest's linear memory as seen from
|
|
150
|
-
/// `caller`. Returns `None` when `memory` is not exported or the slice
|
|
151
|
-
/// falls outside the live memory range.
|
|
152
|
-
fn read_caller_memory(caller: &mut Caller<'_, HostState>, ptr: i32, len: i32) -> Option<Vec<u8>> {
|
|
153
|
-
let mem = match caller.get_export("memory") {
|
|
154
|
-
Some(Extern::Memory(m)) => m,
|
|
155
|
-
_ => return None,
|
|
156
|
-
};
|
|
157
|
-
let data = mem.data(&caller);
|
|
158
|
-
let start = ptr as usize;
|
|
159
|
-
let end = start.checked_add(len as usize)?;
|
|
160
|
-
data.get(start..end).map(|s| s.to_vec())
|
|
161
|
-
}
|