ReviewOS

zig-utils/zig-js

Private ABI: harden serialized-script owner handles

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

Parents: #493, #495 Related: #865

Problem

Bun__serializeJSValue returns a borrowed byte slice plus an opaque owner handle, and Bun__SerializedScriptSlice__free authenticates release solely by that handle. The process-global registry currently issues sequential integer tokens and stores them in std.AutoHashMapUnmanaged(usize, ...).

A misbehaving native caller can predict another live serialized-script token and free its bytes while the rightful consumer still holds the borrowed slice. This turns a revision-pinned ownership boundary into cross-consumer release and a potential use-after-free. Arbitrary lookup tokens also retain predictable hash placement.

Required design

  • Issue nonzero opaque owner capabilities from secure host entropy, with no counter, address, clock, constant, or deterministic fallback.
  • Store owners in a separately seeded exact identity registry. Install its context only after the first backing allocation succeeds.
  • Reject/resample zero and exact live-token collisions without replacing or releasing the existing owner.
  • Token entropy, context entropy, or allocation failure must publish no handle or partial registry state; serialization must release its structured-clone references and byte allocation through the existing OOM path.
  • Preserve exact bytes/layout, flags, SharedArrayBuffer reference release, duplicate/null/stale/forged free behavior, and thread-safe cross-context use.
  • Reclaim empty registry backing/context after the last owner is consumed.

No-workaround rules

  • No predictable fallback token/seed, address-derived capability, hash-only equality, leaked tombstones, lifetime cap, global lock removal, byte copy to hide ownership bugs, signature/layout change, skipped structured-clone release, or relaxed duplicate/stale handling.

Acceptance

  • Deterministic zero/live-collision tests preserve the existing owner and install one unique nonzero capability.
  • Legacy integer collisions disperse under separately keyed exact hashing; lookup/removal remain exact.
  • Token/context entropy and first-allocation failures leave an empty, unseeded, retryable registry without leaking owned bytes/references.
  • Duplicate/null/stale/forged and concurrent owner releases are inert and cannot release a different live slice.
  • Focused serialization tests pass in Debug, ReleaseSafe, and TSan; full units, structured-clone/threadfuzz, public C API, and pinned Home/Bun ABI audits/runtime remain exact.
9 days ago

Implemented and shipped in c6642bb2.

The private ABI now uses nonzero secure-entropy owner capabilities and a separately seeded exact identity registry. Zero and live collisions are resampled; entropy/allocation failures publish no state; empty registries release backing and seed state; and release remains serialized with exactly one winner.

Validation:

  • focused owner capability tests: Debug 2/2, ReleaseSafe 2/2, TSan 2/2 with no leak/race report
  • focused structured serialization: Debug 1/1, ReleaseSafe 1/1, TSan 1/1 with no leak/race report
  • broader structured-clone unit group: 12/12
  • deterministic threadfuzz: 400/400 from seed 1
  • exact clean full suite at the committed tree: 2,287 passed, 1 skipped, 0 failed, 0 leaked across 10 shards
  • public C audit: 117/117 with 26 extensions and 460 private exports
  • Home public ABI: 50/50; Home private ABI: 447/447; Bun private ABI: 437/437
  • private JSType audit: Home 97, Bun 98, shared 97, Bun-only 1, renumbered 70
  • Home private runtime/value shims: 392/392
  • docs build: 50 pages; link check: 328/328

Sign in to comment on this issue.