docs: add Lind-Wasm threat model#1295
Conversation
End-to-End Test ReportTest Previewgrate harnessGrate Test Report
Cases
static harnessTest ReportDeterministic TestsSummary
Test Results by Category
Fail TestsSummary
wasm harnessTest ReportDeterministic TestsSummary
Test Results by Category
Fail TestsSummary
Test Results by Category
C++ harnessSummary
Cases
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
JustinCappos
left a comment
There was a problem hiding this comment.
Most of this is for Lind, not specifically Lind-Wasm. I don't know if it's worth making that clearer here. I do know have a large cleanup project once we start to make that transition.
|
|
||
| It cannot, by the Wasm memory model rather than any policy check, address host | ||
| memory, issue raw Linux syscalls, alter JIT output, or reach another cage's | ||
| memory. |
There was a problem hiding this comment.
Does it make sense to include this:
Wasm runtimes also prohibit access to virtual files within the /proc/self directory. This prevents cages from accessing host information such as secrets through the likes of /proc/self/mem.
There was a problem hiding this comment.
Wasm runtimes also prohibit access to virtual files within the /proc/self directory
This feature is provided by wasi API, which is not used in our lind-wasm implementation. lind-wasm provides fs isolation by enforce chroot at initialization -- only gives cage/grates access to lindfs/ -- but doesn't prohibit access to /proc/self inside lindfs.
|
|
||
| **Case 5: cage or grate against the runtime or kernel (U).** Neither has a path | ||
| downward. The runtime's state is host memory it cannot address (Section 4), and | ||
| the only way up is a runtime bug, which is Case 4. So these cells are unaffected. |
There was a problem hiding this comment.
Further up you mention that a cage can cause a fault in RawPOSIX:
Either it travels down tagged with its originating cage and RawPOSIX faults if it falls outside that cage's address space, or the grate pulls the bytes in with the
copy-from-cage call, which checks the same provenance before copying.
Does this mean a cage can cause the runtime to crash, or will this fault be contained?
My observation is that it kills the whole runtime (see attached code and log).
There was a problem hiding this comment.
Yeah I have same confusion here.
Section 5 says a compromised cage can call host imports and syscall APIs with arbitrary inputs, including make_syscall, register_handler, and copy_handler_table_to_cage. That is a direct input path into 3i/RawPOSIX/Wasmtime.
Also Fredrik's comment showing malformed pointer behavior can kill the whole runtime... I'm not sure should we make this more precise here..?
There was a problem hiding this comment.
This seems like a bug to me yes? We shouldn't be able to kill the runtime like this.
There was a problem hiding this comment.
a cage should be designed to not crash host, if that happens, this is a bug that should be fixed immediately. We shouldn't rely on current lind implementation to define/test threat model as it could have bugs, threat model is a more high level design stuff where the implementation should follows
|
|
||
| **Case 5: cage or grate against the runtime or kernel (U).** Neither has a path | ||
| downward. The runtime's state is host memory it cannot address (Section 4), and | ||
| the only way up is a runtime bug, which is Case 4. So these cells are unaffected. |
There was a problem hiding this comment.
Yeah I have same confusion here.
Section 5 says a compromised cage can call host imports and syscall APIs with arbitrary inputs, including make_syscall, register_handler, and copy_handler_table_to_cage. That is a direct input path into 3i/RawPOSIX/Wasmtime.
Also Fredrik's comment showing malformed pointer behavior can kill the whole runtime... I'm not sure should we make this more precise here..?
| | Victim \ Attacker | Cage A | Grate B | Cage C | Grate D | Runtime | Kernel+HW | | ||
| | --- | --- | --- | --- | --- | --- | --- | | ||
| | **Cage A** | N/A | CC | RE | RE | KO | KO | | ||
| | **Grate B** | FE | N/A | RE | RE | KO | KO | |
There was a problem hiding this comment.
I think Grate B only has RE against unrelated Cage C / Grate D is not precise enough.. Actually a grate can copy from arbitrary cage IDs (from the compromised-grate section and our current implementation)
|
|
||
| **P4: handler-table integrity.** The 3i logic and per-cage handler tables are | ||
| host memory, unreachable from any cage (Section 4), so routing cannot be tampered | ||
| with even if the 3i policy logic has a bug. A cage influences routing only |
There was a problem hiding this comment.
routing cannot be tampered
with even if the 3i policy logic has a bug
This claim might be too strong. The routing correctness needs to depend on correct 3i scoping checks
|
|
||
| It cannot, by the Wasm memory model rather than any policy check, address host | ||
| memory, issue raw Linux syscalls, alter JIT output, or reach another cage's | ||
| memory. |
There was a problem hiding this comment.
Wasm runtimes also prohibit access to virtual files within the /proc/self directory
This feature is provided by wasi API, which is not used in our lind-wasm implementation. lind-wasm provides fs isolation by enforce chroot at initialization -- only gives cage/grates access to lindfs/ -- but doesn't prohibit access to /proc/self inside lindfs.
| ## 2. Methodology | ||
|
|
||
| We do not sort components into trusted and untrusted, because that hides the fact | ||
| that a grate is trusted by the cages it isolates and by nothing else. Instead we |
There was a problem hiding this comment.
because that hides the fact that a grate is trusted by the cages it isolates and by nothing else
Probably a better way to say is,
We do not sort components into trusted and untrusted; there is no global notion of trust. Instead, each component is trusted by a specific set of other components — a grate, for example, is trusted by the cages it isolates and by nothing else.
|
|
||
| ### Compromised grate | ||
|
|
||
| A grate that is compromised can observe, change, drop, or fake results for any |
There was a problem hiding this comment.
In earlier section, it is mentioned
A grate is trusted only by its own descendant cages, and only to enforce their policy.
Does having a grate compromised affect the trust relationship in anyway?
Or is trust and a component getting compromised not related?
I think wasm related is specifically the P6 in Section 8 - Security Properties. In general, any SFI can guarantee cross-cage memory isolation etc. |
|
One thing not discussed is about kernel attack surface reduction or if attacks targeting kernel is made harder through Lind design. Some thoughts on this.. There are two cases here : 1) In a conventional Linux environment, an attacker who finds a memory-safety bug in the application — a buffer overflow, a use-after-free, a format string vulnerability — can exploit it to gain controlled execution within the process and then immediately leverage that foothold to issue arbitrary syscalls with attacker-chosen arguments, targeting known vulnerabilities in the kernel's syscall handlers. 2) Even without fully compromising the application's control flow, an attacker who can influence what data the application processes — through a malicious file, a crafted network packet, or attacker-controlled input that flows into a syscall argument — can steer the application into making a syscall that triggers a kernel bug without the application itself being "exploited" in the traditional sense. In both cases, the kernel's attack surface is the full Linux syscall table, reachable with arbitrary argument values, and a single kernel vulnerability reachable through this path can result in privilege escalation, arbitrary memory corruption across all processes, or a full system compromise. In Lind, both attack paths are disrupted by the same structural property: a cage's only route to the OS is through lind_syscall → 3i → RawPOSIX → kernel. Even if an attacker fully exploits an application cage and achieves arbitrary Wasm code execution, they cannot issue raw kernel syscalls directly — every syscall is intercepted by RawPOSIX, which validates all pointer arguments against the cage's vmmap, enforces unconditional policy rules regardless of argument values, and forwards to the kernel only the subset of operations it deems well-formed and cage-appropriate. A syscall argument deliberately crafted to trigger a specific kernel bug must pass through this validation layer first. Critically, this defence holds even when the application cage is fully compromised — because the interposition is not inside the application but in the trusted host code the cage cannot modify or bypass. |
I do think some of this has merit, I'll try to integrate some here. What I think we want to avoid is a "popular paths" style argument in surface reduction, since at this point its really just "we didnt implement these syscalls", even though something like that could be done with a grate. |
Summary
Adds a threat model document for Lind-Wasm to the internal docs, plus the actor-topology figure it references.
docs/internal/threat-model.md— actors, trust relationships (TCB vs. trusted policy surface), attacker model, the attacker×victim matrix with per-cell reasoning, security properties (P1–P6), and out-of-scope items.docs/images/doc-images/actor-topology.png— Figure 1, the actor topology.mkdocs.ymlnav so it's linked in the published site.Notes
docs/images/doc-images/convention; the relative link resolves fromdocs/internal/.