ReviewOS

zig-utils/zig-js

Objects: securely seed named metadata and order indexes

#851
Closed chris opened this 8 days ago ·
8 days ago

Parents: #493, #478 Related: #530, #532, #759, #762, #848, #850

Problem

Ordinary property values use collision-independent Shape indexes, but several Object-owned side tables still rebuild attacker-controlled exact property/private names into default-context native string maps: accessor descriptors, attribute overrides, private brands, and C-host accessor descriptor cells. Creation-order reconstruction and named-data compaction also use default-context scratch membership maps over the same source-controlled names. An attacker can therefore bypass hardened Shape lookup and recover predictable collision-heavy placement in long-lived metadata and repeated reflection/deletion paths.

Scope

  • Give each Object cold sidecar one lazy unpredictable exact-byte hash context shared by accessor, attribute, private-brand, and C-host accessor-cell maps.
  • Derive production contexts from the current Shape key source when available; a shape-less first metadata insertion must fail closed through secure engine entropy.
  • Reuse the installed Object context for creation-order reconstruction and named-data compaction; shape-only scratch paths derive a transient context from the immutable Shape source without storing per-map state.
  • Keep empty/metadata-free objects and scratch paths allocation- and entropy-free. Publish the context only after the first successful semantic insertion; failed entropy/allocation or multi-store publication must expose no entry or installed context.
  • Preserve property-lock/accessor-gate synchronization, atomic sidecar publication, exact owned/borrowed key lifetime, getter/setter cells, attributes, private-brand checks, deletion/re-add ordering, C host callbacks, OOM rollback, moving/concurrent GC, finalization, and Context teardown.
  • Keep Object in its existing GC slab and ObjectColdState within its existing 256-byte cell allocation; do not add seed/context headers to each map.

No-workaround rules

  • No property/private-name count or length cap, blacklist, source normalization, public/address/time-derived seed, deterministic fallback, hash-only equality, linear fallback presented as hardening, duplicated metadata cache, skipped reflection/brand/descriptor validation, or weakened accessor/attribute/delete semantics.
  • No per-name/per-lookup/per-map OS entropy request, global mutable seed, unsynchronized lazy publication, benchmark-specific path, public API/ABI change, or unrelated stack/job/Worker work.

Acceptance

  • Every long-lived Object accessor/attribute/private-brand/C-host accessor-cell lookup, insertion, removal, and membership operation uses the owning Object installed context.
  • Creation-order reconstruction and named-data compaction use an installed or Shape-derived secure exact-byte context; empty paths request no context.
  • Default-seed collision families disperse under a fixed keyed context with exact equality, including embedded NUL names, and all long-lived maps demonstrably share one context.
  • First-writer/OOM publication is atomic; accessors, attributes, brands, custom descriptor cells, deletion/re-add order, and finalization retain exact key ownership with zero leaks.
  • Normal, ReleaseSafe, TSan/no-GIL, moving/concurrent GC, bounded-heap, C-API, Proxy/reflection, class/private-brand, and OOM tests pass.
  • Exact-parent Object/Reflect/Proxy/class/private-name inventories have nonzero accounting and zero regressions; required-VM parity has zero new divergence.
  • Object slab class and ObjectColdState allocation bound remain unchanged; full unit and threadfuzz gates pass.
8 days ago

Implemented and verified in fix(object): seed named metadata maps (#851).

The change installs one lazy unpredictable exact-byte context in the Object storage sidecar and shares it across accessor, attribute, private-brand, and C-host descriptor-cell maps. Shape-backed objects derive it from the realm Shape key source; shape-less first insertions use secure engine entropy. Creation-order reconstruction and named-data compaction use installed or transient Shape-derived contexts without persisting scratch state. Accessor and data-descriptor first publication are failure-atomic, and map headers remain seed-free. Object stays in its 128-byte slab and ObjectColdState remains within the 256-byte allocation bound.

Verification:

  • dedicated Debug and ReleaseSafe hardening probes: 6/6, zero leaks
  • TSan/no-GIL: dedicated 6/6 plus Proxy, Object reflection, and private-brand shared-realm cases, zero races/leaks
  • moving/concurrent GC, bounded deep-shape, named deletion/order/OOM, accessor finalization, public C API, and Home private ABI gates passed
  • full units: 2,257 pass, 1 platform skip, 0 fail, 0 leak
  • threadfuzz: 400 programs, 0 failures
  • exact-parent Test262: Object 3,411; Reflect 153; Proxy 311; statement classes 4,367; expression classes 4,059 — 12,301 pass, 0 fail on both parent and candidate; logs byte-identical
  • required VM: 12,301 agree, 0 diverge

Sign in to comment on this issue.