ReviewOS

zig-utils/zig-js

Wasm: harden streaming compiler capability handles

#865
Closed chris opened this 9 days ago ·
9 days ago

Parents: #493, #486, #495 Related: #864

Problem

The process-global private Wasm streaming compiler registry issues sequential integer tokens and stores them in std.AutoHashMapUnmanaged(usize, ...). JSC__Wasm__StreamingCompiler__addBytes is a revision-pinned void ABI with no Context/VM argument, so the opaque token is its only authority boundary. A misbehaving native caller can predict another live feed's token and append bytes to it, while chosen arbitrary handles retain predictable registry placement.

The boundary already rejects null, stale, forged, and foreign-VM handles without dereferencing them, but sequential issuance does not make a live handle an unguessable capability.

Required design

  • Issue nonzero opaque capability tokens from secure host entropy, with no counter, address, clock, constant, or deterministic fallback.
  • Replace default integer hashing with a separately keyed exact registry context derived from secure host entropy.
  • Install the registry context only after the first backing allocation succeeds. Token entropy failure, context entropy failure, or allocation failure must return no handle and leave empty state retryable.
  • Retry an exact live-token collision without replacing or exposing the existing entry. Preserve locked concurrent feeds, same-VM sibling finalization, foreign-VM refusal, finalization stickiness, explicit release, and Context teardown retirement.
  • Keep arbitrary inputs lookup-only and never dereference opaque tokens.

No-workaround rules

  • No predictable fallback token/seed, token truncation, address-derived capability, hash-only equality, global lock removal, lifetime cap, leaked tombstone set, blind acceptance of collision, ABI signature change, or relaxed foreign/stale/teardown checks.

Acceptance

  • Deterministic tests prove zero and live-token collisions retry to a unique nonzero capability without mutating the existing entry.
  • A legacy integer-hash collision family disperses under the keyed exact context with exact lookup/removal.
  • Token/context entropy failure and first allocation failure publish no handle, context, or table; exact retry succeeds.
  • Concurrent feed/finalize/release, same-VM siblings, foreign/stale/forged handles, and Context teardown retain the pinned lifecycle contract.
  • Focused tests pass in Debug, ReleaseSafe, and TSan; Wasm streaming/API/spec, full units, public C API, and pinned Home/Bun ABI audits/runtime remain exact.
9 days ago

Implemented and pushed to main in fix(wasm): harden streaming compiler handles (#865).

The pinned context-free JSC__Wasm__StreamingCompiler__addBytes signature is unchanged. Handles are now nonzero capability tokens sampled from secure host entropy, and the process registry uses a separate secure seed with exact token equality. A zero or live-token collision is resampled. Token entropy, seed entropy, and first backing-allocation failures return no handle and publish no context or partial table. Lookup remains lock-serialized and never dereferences caller tokens.

Validation:

  • deterministic capability/rollback and legacy-collision tests: 2/2, including exact existing-entry preservation, zero/live-token resampling, independent seeded placement, entropy failure, first-allocation failure, and exact retry;
  • complete streaming group: 6/6 in Debug, ReleaseSafe, and TSan, 0 failures/leaks/races;
  • full Wasm API group: 47/47 in Debug, including precise GC, shared/no-GIL memory, worker, exception, and streaming lifetimes;
  • pinned external StreamingCompiler lifecycle fixture: Home and Bun both pass in Debug, ReleaseSafe, and TSan; Home private audit 447/447 and Bun private audit 437/437;
  • public C audit 117/117, Home public 50/50, private JSType audit clean, Home runtime shims 392/392;
  • wasm-spec-eval builds; packed wg-1.0 JSON is byte-identical to exact parent 4086df83 (SHA-256 6a2e6e895a5a2935b68fce07af33cd1cadf6f151846574935b6dff4204d6ccbf): 73 files, 18,778 pass, 13 existing failures, 479 skip, 0 crash;
  • default threadfuzz: 400 programs from seed 1, 0 failures;
  • exact pushed commit in a clean checkout: 2,285 passed, 1 skipped, 0 failed, 0 leaked across 10 shards;
  • hash-guarded ABI contract regenerated through its owning audit; docs manifest/build passed for 50 pages and the offline link gate passed 328/328 files.

The unchanged 13 packed-spec failures are reported as exact-parent parity, not as a passing conformance gate. No ABI signature, token dereference, fallback seed, address-derived capability, tombstone set, lifetime cap, or relaxed ownership check was introduced.

Sign in to comment on this issue.