freepdfeditor/docs/adr/0004-two-process-trust-boun...

3.3 KiB

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.