71 lines
3.3 KiB
Markdown
71 lines
3.3 KiB
Markdown
# ADR-0004 — Two-process model with the IPC as a bidirectional trust boundary
|
|
|
|
* **Status**: Accepted
|
|
* **Date**: 2025-07-25
|
|
* **Plan reference**: §2.1
|
|
|
|
## Context
|
|
|
|
PDF parsers are among the most heavily exploited attack surfaces in desktop
|
|
software, and we are writing a new one. A single-process editor means a
|
|
parser bug is a direct path to the user's files, network, and other
|
|
applications. Sandboxing is the one thing in the plan that is genuinely
|
|
painful to retrofit (§14 step 8), so the process split must be decided
|
|
before any parsing code lands.
|
|
|
|
The naive read of "sandbox the parser" treats the sandbox as protecting *us*
|
|
from *the document*. The decision recorded here is that the IPC boundary is
|
|
a trust boundary in **both** directions: the document process is compromised
|
|
by hostile input, so anything it sends is itself hostile to the unsandboxed
|
|
UI process. A compromised document process attacking the UI is the obvious
|
|
escape path and the one people forget.
|
|
|
|
## Decision
|
|
|
|
**Two processes.** The UI process (Qt) holds the canvas, panels, tools,
|
|
command dispatch, undo, and render-surface compositing; it does no untrusted
|
|
parsing. The document process (sandboxed) holds file I/O, parsing, the object
|
|
model, content streams, rasterization, re-emission, and save. One document
|
|
process per open document; a crash loses one tab, not the app.
|
|
|
|
* **IPC**: local socket, Cap'n Proto messages, shared memory for raster
|
|
tiles (no copies on the hot path).
|
|
* **Sandbox**: seccomp-bpf + user namespaces (Linux), App Sandbox with a
|
|
minimal entitlement set (macOS), AppContainer + low-integrity token
|
|
(Windows). The document process gets no network access and no filesystem
|
|
access beyond fds handed to it by the UI process.
|
|
* **Bidirectional trust boundary.** The UI validates every message (bounds,
|
|
counts, string encodings, shared-memory extents) and never indexes,
|
|
allocates, or size-computes directly from a document-supplied number.
|
|
Cap'n Proto arena reader limits are set explicitly, not left at defaults.
|
|
* **Fuzz the UI-side deserializer as its own harness** (§8.2) — a
|
|
compromised document process attacking the unsandboxed UI is the obvious
|
|
escape path and the one people forget.
|
|
|
|
A crash in the document process is recovered by the UI: restart it and
|
|
replay the journal (§6.4).
|
|
|
|
## Consequences
|
|
|
|
**Positive.** A parser bug cannot directly reach the user's files or
|
|
network. A document-process crash loses one tab, not the app — and is
|
|
recoverable. The bidirectional framing means the escape path people forget
|
|
is covered by an explicit gate.
|
|
|
|
**Negative.** The process split has a real cost on open latency (measured at
|
|
M0, §14 step 8). IPC adds complexity to every edit and every render tile.
|
|
Sandboxing on all three platforms is platform-specific work that has to be
|
|
maintained.
|
|
|
|
**Neutral.** Two windows on the same file share one document process (§6.4).
|
|
|
|
## Alternatives considered
|
|
|
|
* **Single process** — rejected; a parser bug is a direct path to the
|
|
user's machine.
|
|
* **Sandbox only the parser, IPC treated as trusted** — rejected; a
|
|
compromised document process attacking the unsandboxed UI is the escape
|
|
path people forget (§2.1).
|
|
* **Out-of-process renderer, in-process parser** — rejected; the parser is
|
|
the larger CVE surface, not the renderer. PDFium (the renderer) is
|
|
battle-tested; our parser is new. |