ReviewOS

zig-utils/zig-js

C API: validate opaque inspector session handles before dereference

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

Parents: #493, #495 Related: #156, #396, #870

Problem

ZJSInspectorSessionRelease and ZJSInspectorSessionDispatch cast an arbitrary embedder-provided ZJSInspectorSessionRef and read session.state before proving that the address names a live registered session. The process registry is an ordered linear pointer list used by broadcasts, and only the private reporter-agent lookup currently validates membership before dereference.

The worker transport has the same boundary: ZJSWorkerInspectorSessionDispatch, Pump, and Release cast and inspect the supplied ZJSWorkerInspectorSessionRef without any process membership registry. Null is inert, but a forged or retired non-null handle can therefore be dereferenced before rejection. Returning allocator addresses also exposes session allocation identity and permits stale-address aliasing if storage is later reused.

Required design

  • Return nonzero secure capability tokens rather than allocator addresses for both opaque session types; token entropy must be independent from bucket hashing and live-token collisions must retry without overwrite.
  • Extend the existing mutex-protected process inspector registry with one lazy, securely seeded exact-token index whose tagged values distinguish context sessions from worker sessions.
  • Preserve context-session creation order for broadcasts while making arbitrary handle validation exact and constant expected time.
  • Publish a session only after token generation and every required ordered/index allocation succeeds; entropy or backing-allocation failure must roll back without exposing a partial handle or leaking registry state.
  • Validate exact membership, transport kind, and owner-thread/liveness state under the registry lock before dereferencing anything obtained from a caller-provided handle.
  • Retain context sessions across dispatch/reentrant callbacks so release remains deferred until the active operation has unwound.
  • Remove exactly once on physical teardown; reset/free an empty index so a later lifecycle obtains fresh entropy.
  • Preserve worker queue, pump, detach fallback, worker-first shutdown, context pause ownership, broadcast order, and ABI signatures/layouts.

No-workaround rules

  • No raw-pointer handle or dereference before membership validation, predictable or address-derived token/seed, shared token/hash entropy, hash-only equality, linear validation scan, tombstone-only retirement, leaked empty allocation, arbitrary registry cap, disabled reentrancy, weakened thread affinity, serialized global inspector callback, or ABI change.

Acceptance

  • Null, forged, wrong-transport, foreign-thread, duplicate-release, and retired context inspector capabilities are inert; dispatch returns false without dereference.
  • The same guarantees hold for worker inspector dispatch/pump/release, with invalid pump returning closed.
  • Default-seed collision families disperse in the secure tagged index; exact live-token collision retries without overwrite or cross-transport confusion.
  • Token/hash entropy and first allocation failures are empty, unseeded, leak-free, and retryable; final removal resets storage and later insertion obtains fresh entropy.
  • Multi-session broadcast order, callback-driven release, detach/pause ownership, worker-first close, and concurrent/wrong-thread behavior remain exact.
  • Focused tests pass in Debug, ReleaseSafe, and TSan; C inspector and worker inspector fixtures, ABI audits, threadfuzz, full units, and docs gates pass.
9 days ago

Implemented and pushed to main in 516a8d59.

Evidence:

  • 8/8 capability-focused tests passed.
  • 24/24 inspector tests passed in Debug, ReleaseSafe, and TSan with zero failures or leaks.
  • Public C/C++ and pinned Home/Bun private inspector fixtures passed in Debug and ReleaseSafe.
  • Pinned Home/Bun private inspector fixtures passed under TSan.
  • threadfuzz: 400 programs, zero failures.
  • Full unit suite: 2,295 passed, 1 skipped, 0 failed, 0 leaked across 2,296 tests.
  • Docs build: 50 pages; offline link check: 328 files, all links resolve.
  • Public/private ABI audits remain complete with zero pending/unclassified symbols.

The public C-host TSan linker wiring defect discovered during validation is separately tracked in #872; it does not affect the successful TSan Zig inspector suite or private fixtures.

Sign in to comment on this issue.