c319604d382409129f78d2f7a3da118a5bee259f [M151] Sanitize presentation attribute cache hash using EnsureValidHash
The bug at a glance
A hash collision with the HashTraits DeletedValue sentinel (0xFFFFFFFF) causes an Oilpan HeapHashMap bucket to be treated as deleted and skipped during tracing, so a live CSSPropertyValueSet is swept while still referenced, yielding a use-after-free returned from a web-reachable cache lookup. High because presentation attributes are fully web-content reachable, tempered from critical by the probabilistic hash condition.
An attacker crafts elements/attributes so ComputePresentationAttributeCacheHash produces 0xFFFFFFFF, poisoning the presentation-attribute cache bucket so a later lookup for the same key returns a freed CSSPropertyValueSet the renderer then uses.
Root cause
ComputePresentationAttributeCacheHash returned HashInts(…) directly, without routing through EnsureValidHash which maps the HashTraits sentinel values 0 and 0xFFFFFFFF to safe ones. When the computed hash equals 0xFFFFFFFF (the DeletedValue sentinel), the entry is stored in a HeapHashMap bucket that Oilpan treats as deleted; GC then skips tracing that bucket, so the referenced CSSPropertyValueSet is swept even though the map still holds a Member to it. A subsequent cache lookup for the same element key returns the dangling (freed) CSSPropertyValueSet pointer, a use-after-free. The fix wraps the result in EnsureValidHash, matching ElementDataCache and MatchedPropertiesCache.
Key code
Filter sentinel hashes (0 / 0xFFFFFFFF) via EnsureValidHash
- return HashInts(key.tag_name->ExistingHash(), attribute_hash);
+ return EnsureValidHash(
+ HashInts(key.tag_name->ExistingHash(), attribute_hash));
Patch walkthrough
third_party/blink/renderer/core/dom/presentation_attribute_style.cc— Wraps the presentation-attribute cache hash in EnsureValidHash and includes hash_traits.h, preventing the hash from equaling the HashTraits empty(0)/deleted(0xFFFFFFFF) sentinels that would make a HeapHashMap bucket be treated as deleted and skipped by Oilpan tracing, which would otherwise free a still-referenced CSSPropertyValueSet and cause a UAF on the next lookup.
Background
Presentation attribute cache — A HeapHashMap cache mapping element presentation-attribute keys to computed CSSPropertyValueSet style objects.
EnsureValidHash — WTF helper that remaps the reserved HashTraits sentinel hashes (0 empty, 0xFFFFFFFF deleted) to valid non-sentinel values.
Oilpan HeapHashMap tracing — Garbage collection traces live buckets; buckets whose hash equals the deleted sentinel are treated as deleted and not traced, so their referents can be swept.
CSSPropertyValueSet — Oilpan-managed object holding parsed CSS declarations; here cached per element presentation-attribute signature.
Vulnerability window
- Reachability — A page sets presentation attributes on elements, populating the presentation-attribute style cache.
- Trigger — Attributes are chosen so ComputePresentationAttributeCacheHash yields 0xFFFFFFFF, storing the entry in a bucket Oilpan treats as deleted.
- Primitive — GC skips tracing the poisoned bucket and sweeps the still-referenced CSSPropertyValueSet, leaving a dangling Member; a later lookup returns the freed pointer (use-after-free).
- Escalation — Reclaiming the freed CSSPropertyValueSet allocation could enable type confusion or a write primitive toward renderer compromise (inferred).
Proof of concept
Conceptually: create elements whose tag name and presentation-attribute set hash to 0xFFFFFFFF so the cache bucket is marked deleted, force a garbage collection to sweep the referenced style object, then re-query the same element/attribute signature so the cache returns the freed CSSPropertyValueSet. Finding the colliding attribute set is the main effort; no weaponized trigger is provided.
Exploitation
- Hash grind — Search for a tag/attribute combination whose computed hash equals the 0xFFFFFFFF deleted sentinel (inferred).
- Poison cache — Insert that element to place its CSSPropertyValueSet in a bucket Oilpan will treat as deleted.
- Sweep — Trigger GC so the still-referenced style object is swept, creating a dangling Member.
- Use — Re-trigger a cache lookup for the same key and leverage the returned freed pointer (inferred).
Detection & hunting
For defenders and detection engineers:
- grep for HashInts(…) returns feeding HeapHashMap keys without EnsureValidHash — Audit cache hash computations in blink that store Oilpan Member values; any unfiltered hash can hit the 0/0xFFFFFFFF sentinels.
- ASAN/Oilpan UAF on CSSPropertyValueSet from presentation-attribute style lookups — Fuzz elements with varied presentation attributes plus forced GC and watch for swept-while-referenced style objects.
Audit directions
- Other blink HeapHashMap caches keyed by a custom hash — Verify each hash passes through EnsureValidHash before use, as ElementDataCache and MatchedPropertiesCache do.
- Custom HashTraits with sentinel 0/0xFFFFFFFF over Oilpan Members — Confirm no code path can produce a key hash colliding with the empty/deleted sentinels and silently drop tracing.