ReviewOS

zig-utils/zig-js

Symbols: securely seed interpreter property-key recovery

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

Parents: #493, #479 Related: #759, #762, #848, #850, #851

Problem

Interpreter.symbols is the remaining default-context runtime string map. It recovers the original Symbol object from the engine encoded property key for reflection and Proxy trap arguments. Although scripts cannot choose the encoded bytes directly, the keys are predictable monotonic \x00s<id> strings: an attacker can precompute a default-Wyhash collision family, create intervening Symbols, and use only selected identities as property keys during one long evaluation. That restores collision-heavy native placement behind otherwise hardened Object/Shape reflection paths.

Scope

  • Give each Interpreter one lazy unpredictable exact-byte Symbol-index context derived from its realm root Shape key source.
  • Use that context for every Symbol recovery lookup and cache insertion, including well-known, registered, Intl fallback, Proxy, and reflection paths.
  • Publish the context only after the first successful map insertion; derivation or allocation failure must expose neither an entry nor an installed context.
  • Keep empty and lookup-only interpreters allocation- and entropy-free, and retain arena ownership with no per-entry or per-map seed allocation.
  • Preserve Symbol identity, registry persistence across short-lived Interpreter instances, embedded-NUL internal encodings, moving/concurrent GC tracing and relocation, Proxy/reflection order, Intl fallback behavior, OOM propagation, and required-VM parity.

No-workaround rules

  • No Symbol count/id cap, skipped identity cache, description/key rewriting, public/address/time-derived or deterministic fallback seed, hash-only equality, linear scan presented as hardening, global mutable seed, per-Symbol entropy request, or duplicated registry.
  • No unrelated Object, Environment, stack, job, Worker, Promise, collection, or public/private ABI changes.

Acceptance

  • Every Interpreter Symbol-index lookup and insertion uses one installed realm-derived exact-byte context.
  • Predictable default-seed collision IDs disperse under a fixed keyed context while embedded-NUL equality and Symbol identity remain exact.
  • Empty/miss paths install no context; first derivation/allocation failure publishes no entry/context.
  • Symbol registry, Proxy/Reflect/Object symbol reflection, Intl fallback, moving/concurrent GC, OOM, normal, ReleaseSafe, and TSan/no-GIL tests pass.
  • Exact-parent Symbol/Object/Reflect/Proxy inventories have nonzero accounting and zero regressions; required-VM parity has zero new divergence.
  • Full unit and threadfuzz gates pass.
9 days ago

Implemented and pushed to main in ce1225a5.

Evidence:

  • dedicated collision/OOM tests: 2/2 in Debug, ReleaseSafe, and TSan
  • Symbol-focused unit coverage: 27/27; active-interpreter GC relocation: 1/1
  • full unit suite: 2,259 pass, 1 platform skip, 0 fail, 0 leak across 2,260 tests
  • threadfuzz: 400 programs, 0 failures
  • exact-parent Test262: Symbol 98, Object 3,411, Reflect 153, Proxy 311; 3,973 pass and 0 fail on both revisions, with byte-identical logs
  • required-bytecode parity: 3,973 agree, 0 diverge
  • public C API: 117/117 complete; Home private ABI: 447 implemented, 0 pending; 392/392 runtime shims passed

The index now uses one lazy root-Shape-derived exact-byte context per Interpreter. Misses remain derivation-free and the context is published only after a successful insertion.

Sign in to comment on this issue.