85c3f8f61abfd66fc1491e5a96aaf8c25f4f4fc4 [M152] Sanitize presentation attribute cache hash using EnsureValidHash
The bug at a glance
The commit message and diff describe a genuine use-after-free: an unsanitized hash equal to the HashTraits DeletedValue sentinel makes Oilpan skip tracing the bucket, so a live CSSPropertyValueSet is swept while the HeapHashMap keeps a reference, and a later lookup returns a freed pointer; a renderer heap UAF reachable from DOM content is high severity.
An attacker-controlled page can shape element tag names and presentation-attribute sets so the cache key hash collides with the deleted-bucket sentinel, inducing premature GC of a cached style object that is then dereferenced on the next lookup.
Root cause
ComputePresentationAttributeCacheHash returned HashInts(tag_hash, attr_hash) directly, without EnsureValidHash, so the result could be one of the HashTraits sentinels (0 or 0xFFFFFFFF). A hash equal to 0xFFFFFFFF (DeletedValue) causes the Oilpan HeapHashMap to place the Member in a bucket treated as deleted; GC then skips tracing that bucket, sweeps the entry, yet the map still holds the stale Member. A subsequent cache lookup for the same key returns the freed pointer (use-after-free). The fix wraps the output in EnsureValidHash to remap sentinel values to a safe hash, matching ElementDataCache and MatchedPropertiesCache.
Key code
Sanitize cache hash so it can never equal the deleted/empty HashTraits sentinels
- 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— Adds hash_traits.h and wraps the computed presentation-attribute cache hash in EnsureValidHash so the value can never collide with HashTraits sentinels (0 / 0xFFFFFFFF); this prevents an Oilpan HeapHashMap bucket from being misclassified as deleted and its live CSSPropertyValueSet from being swept, closing a use-after-free.
Background
Presentation attribute cache — A HeapHashMap caching computed CSSPropertyValueSet style for elements keyed by tag name plus presentation attributes/values.
EnsureValidHash — WTF helper that remaps hash values colliding with HashTraits empty/deleted sentinels (0 and 0xFFFFFFFF) to a valid hash.
Oilpan HeapHashMap deleted bucket — A bucket whose hash equals DeletedValue is treated as a tombstone and is not traced during garbage collection, so its referent can be swept.
Vulnerability window
- Reachability — Page content with elements bearing presentation attributes populates the presentation-attribute style cache during style resolution.
- Trigger — A tag-name/attribute combination hashes to 0xFFFFFFFF, so the cached Member lands in a bucket treated as deleted (inferred, probabilistic).
- Primitive — Garbage collection skips the deleted bucket and sweeps the CSSPropertyValueSet while the map still references it, producing a dangling pointer.
- Escalation — A later cache lookup for the same key returns and dereferences the freed object, giving a UAF that controlled reallocation could turn into corruption (inferred).
Proof of concept
Conceptually: generate many elements whose tag name and presentation-attribute set vary so that one combination’s HashInts result equals 0xFFFFFFFF, cache its style, force a garbage-collection cycle, then query the same element/key again to hit the freed CSSPropertyValueSet. Finding a colliding key is a ~1-in-2^32 search over attacker-chosen inputs. No exploit code.
Exploitation
- Key search — Enumerate tag/attribute combinations until one hashes to the DeletedValue sentinel (inferred).
- Populate — Resolve style for that element so the freed-prone Member is stored in the deleted-looking bucket (inferred).
- Free — Trigger Oilpan GC so the untraced entry is swept while the map keeps the reference (inferred).
- Reuse — Groom the heap and re-query the key to dereference the dangling CSSPropertyValueSet (inferred).
Detection & hunting
For defenders and detection engineers:
- grep for HashInts(…) returned directly from a Compute*Hash / cache-key hash function without EnsureValidHash — Flag any Oilpan HeapHashMap keyed by a raw composed hash that is not passed through EnsureValidHash.
- ASAN/Oilpan heap-use-after-free on CSSPropertyValueSet in presentation attribute style lookups — Fuzz varied tag/attribute content with forced GC and watch for UAF in presentation_attribute_style.cc.
Audit directions
- All Blink Oilpan caches keyed by a custom hash (HeapHashMap/HeapHashSet) — Verify every cache-key hash function wraps its result in EnsureValidHash like ElementDataCache and MatchedPropertiesCache.
- third_party/blink/renderer/core style/dom caches — Audit other Compute*CacheHash helpers in core/dom and core/css for missing sentinel sanitization.