ReviewOS

zig-utils/zig-js

Runtime: securely seed declarative environment bindings

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

Parents: #493, #465 Related: #636, #760, #761, #770, #848, #849

Problem

Parser and compiler declaration tables are securely keyed, but evaluated declarative Environment records rebuild source-controlled identifiers into six default-context native hash tables: value bindings, const tags, global lexical tags, named-function immutability tags, deletable eval tags, and module live-binding aliases. An attacker can therefore move a collision family past the hardened frontend and recover collision-heavy placement in long-lived runtime scopes used by both the tree walker and VM.

Scope

  • Give each Environment record one lazy unpredictable exact-byte hash context shared by vars, consts, lexicals, fn_names, deletable, and aliases.
  • Production records derive from the realm root Shape key source; standalone/test records fail closed through secure engine entropy rather than a predictable fallback.
  • Empty/read-only records request no context. A successful first semantic insertion publishes exactly one context; subsequent tags, aliases, lookups, removals, iteration, and direct-eval forwarding reuse it.
  • Preserve the existing binding-lock/private-activation ownership model. Competing first writers must converge on the installed context without racing context state or hashing one table with mismatched contexts.
  • Preserve owned-key lifetime, GC tracing/relocation/finalization, module live bindings, global lexical shadowing, named-function assignment rules, sloppy-eval deletion, direct eval activation views, closures, TDZ, and moving/no-GIL execution.
  • Keep one inline source-or-context state per Environment; do not add a seed/context header to each of the six maps or allocate a separate hash-state object per activation.

No-workaround rules

  • No identifier count/length cap, blacklist, source normalization, public/address/time-derived seed, deterministic fallback, hash-only equality, linear fallback presented as hardening, duplicated environment cache, weakened TDZ/immutability/delete semantics, or skipped frontend/runtime validation.
  • No per-binding/per-map OS entropy request, global mutable seed, unsynchronized lazy publication, or public API/ABI change.

Acceptance

  • Every runtime declarative binding/tag/alias table uses the Environment installed context for lookup, insertion, removal, and membership.
  • Empty environments remain unseeded; first-writer success publishes once; failed first semantic insertion exposes no binding/tag/alias or installed context.
  • Default-seed collision families disperse under a fixed keyed context with exact equality, including embedded NUL names, and all six tables demonstrably share the context.
  • Normal, ReleaseSafe, TSan/no-GIL, moving-GC, OOM, direct-eval/delete, closure, module live-binding, TDZ, and named-function tests pass with zero leaks/races.
  • Exact-parent identifier/environment Test262 inventories have nonzero accounting and zero regressions; required-VM parity has zero new divergence.
  • Full unit and threadfuzz gates pass.
9 days ago

Landed on main as fix(runtime): seed environment binding maps (#850).

Evidence:

  • Normal and ReleaseSafe Environment coverage: 16/16 pass, 0 leaks.
  • TSan Environment coverage: 16/16 pass, including competing first writers and concurrent tracing; focused no-GIL shared-global reader/writer: 1/1 pass.
  • Direct eval: 36/36; modules: 46/46; TDZ: 8/8; moving-GC: 14/14.
  • Exact-parent Test262 inventories: 2,577/2,577 pass, 0 flips across identifier-resolution, eval-code, function-code, let, const, variable, module-code, and dynamic-import.
  • Required-VM parity: 2,577 agree, 0 diverge, byte-identical to the exact parent.
  • Full units: 2,251 pass, 1 platform skip, 0 fail, 0 leak.
  • Threadfuzz: 400 seeded programs, 0 failures.

Sign in to comment on this issue.