Skip to content

Remote peers can force expensive synchronous PBKDF2 via ocap-URL redemption #1036

Description

@sirtimid

A remote peer can force the kernel to run expensive synchronous key derivation by sending redeemURL messages, at a cost that blocks the event loop.

Mechanism

#handleRedeemURLRequest (packages/ocap-kernel/src/remotes/kernel/RemoteHandle.ts:879-889) handles an inbound redeemURL message and passes the peer-supplied string straight to redeemLocalOcapURL (remotes/kernel/remote-comms.ts:339-356), which calls cipher.decrypt.

The cipher is AES_GCM.create() with no options (remote-comms.ts:240), so @libp2p/crypto's password-mode defaults apply: pbkdf2Sync(key, salt, 32767, 16, 'sha256') per operation, synchronous. The salt is read from the ciphertext, so nothing can be cached across calls, and the cost is paid before authentication fails — garbage oids cost exactly as much as valid ones.

Measured

per operation:        4.39 ms
throughput, 1 core:    228 ops/sec

The default per-peer message rate limit is 100/s (remotes/platform/constants.ts:20), so one peer can demand roughly 0.44 CPU-seconds per wall second — about three peers saturate a core. Because pbkdf2Sync is synchronous, the impact is not just throughput: the kernel's event loop stalls in 4.4 ms chunks, so unrelated kernel work pays the latency.

Why this is filed separately from #777

The underlying construction is #777's to review, and the proper fix — not stretching an already-uniform 256-bit key — is a change to the URL format, which needs a version prefix and a transition window (see #777 for both). But this is exploitable today, whether or not that review happens, and mitigations do not depend on it:

  • reject structurally invalid oids before the expensive step (length, base58 validity) — helps against unstructured garbage;
  • bound concurrent or queued redeemURL work per peer, independently of the general message rate limit;
  • move the derivation off the main thread so a stall costs throughput rather than whole-kernel latency.

Filed so the exposure is tracked on its own terms rather than waiting on a review whose timeline is unknown.

Related: #777 (the construction and the real fix), #989 (key custody; same code path, different concern).

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingocap-bug-fixOCAP Kernel bug fix

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions