a8a28009b6c759960a97216f3a068e9cbb20d035 [M150] Reinsert PatternData into pattern map after reconstruction
Triage note: Identical to 60126f0149 (M150 cherry-pick, Fixed: 565742179): find()+pointer and re-insert via Set() instead of writing through a reference the map clear could invalidate.
The bug at a glance
Identical bug and fix to 60126f0149: a use-after-free write in LayoutSVGResourcePattern where a reference into pattern_map_ is held across BuildPatternData, which can clear the map. SVG pattern painting is web-reachable with attacker markup and a UAF write is a strong renderer-process primitive, so it rates high. This is the M150-branch security cherry-pick of the same main-line fix.
Same mechanism as 60126f0149, delivered to a different release line. LayoutSVGResourcePattern held std::unique_ptr& into a pattern_map_ slot and kept using it across BuildPatternData, which can clear pattern_map_ and free that slot — leading to a write through a dangling reference. This object is the M150 stable-branch cherry-pick: refs/branch-heads/7871@{#4420}, Bug: 567784342 (merge-tracking) of Fixed: 565742179, from the same original main commit dedbd3f (main@{#1706535}).
Root cause
The pre-fix code bound std::unique_ptr& pattern_data to pattern_map_.insert(&client, nullptr).stored_value->value, a reference into a WTF::HashMap value slot. BuildPatternData(reference_box, paint_flags) can recursively resolve SVG resources and clear/rehash pattern_map_, freeing the backing the reference points at; the subsequent pattern_data = BuildPatternData(…) and pattern_data->paint_flags = paint_flags then write through a dangling reference (UAF write). The fix replaces the held reference with pattern_map_.find(&client) into a raw PatternData*, builds into a local std::unique_ptr new_pattern_data, captures the raw pointer, asserts CHECK(pattern_data), and re-inserts via pattern_map_.Set(&client, std::move(new_pattern_data)) AFTER the build — so the map bucket is re-resolved post-mutation and no stale reference is dereferenced. The source change is byte-for-byte identical to the M153 instance; only the branch (M150 / branch-heads/7871) and merge bug differ.
Key code
M150 cherry-pick: find()+Set() replaces the held pattern_map_ slot reference (identical to the M153 fix)
auto iter = pattern_map_.find(&client);
PatternData* pattern_data =
(iter == pattern_map_.end() ? nullptr : iter->value.get());
if (pattern_data && pattern_data->paint_flags != paint_flags) {
pattern_data = nullptr;
}
if (!pattern_data) {
auto new_pattern_data = BuildPatternData(reference_box, paint_flags);
pattern_data = new_pattern_data.get();
CHECK(pattern_data);
pattern_map_.Set(&client, std::move(new_pattern_data));
pattern_data->paint_flags = paint_flags;
}
Patch walkthrough
third_party/blink/renderer/core/layout/svg/layout_svg_resource_pattern.cc— The sole change, identical source to the M153 cherry-pick (60126f0149) but applied on the M150 branch (file pre-image hash differs: 85e5ccb1 here vs ec602b7 on M153, reflecting branch drift). Before: std::unique_ptr& pattern_data = pattern_map_.insert(&client, nullptr).stored_value->value held a reference into the map slot and wrote through it (reset()/assignment) after BuildPatternData, which can clear pattern_map_ — a UAF. After: find() into a raw PatternData*, null it on paint_flags mismatch, and on rebuild call BuildPatternData into a local unique_ptr, capture the raw pointer, CHECK(pattern_data), then pattern_map_.Set(&client, std::move(new_pattern_data)) so the write to the map happens after the build with a freshly-resolved bucket. No map reference is held across the build.
Background
LayoutSVGResourcePattern::pattern_map_ — Per-resource WTF::HashMap<client, std::unique_ptr> caching resolved SVG paint data per client.
BuildPatternData re-entrancy — Building a pattern’s tile can recursively resolve other SVG resources and trigger invalidation that clears pattern_map_ during the call, invalidating any reference previously taken into that map.
find()+Set() vs insert().stored_value — insert().stored_value->value yields a reference into the hash-map backing that is unsafe to hold across a mutating call; find() + a post-build Set() re-resolves the bucket and avoids dereferencing a freed slot.
M150 branch — This is the M150 stable cherry-pick (refs/branch-heads/7871@{#4420}, Cr-Branched-From main@{#1639810}, merge bug 567784342) of the same original fix (Fixed: 565742179, dedbd3f, main@{#1706535}) that 60126f0149 delivered to M153 (branch-heads/8010).
Vulnerability window
- Introduction — Same latent defect as 60126f0149: a reference into pattern_map_ held across BuildPatternData, present on the M150 line.
- Report — Original Chromium issue 565742179 (Fixed); M150 merge tracked under bug 567784342.
- Main fix — Original fix dedbd3f9 by Stefan Zager, reviewed by Fredrik Söderquist, Cr-Commit-Position refs/heads/main@{#1706535}.
- M150 cherry-pick — Merged to M150 2026-10-05 via CL 8496896, Cr-Commit-Position refs/branch-heads/7871@{#4420} (Cr-Branched-From main@{#1639810}).
Proof of concept
No test or PoC is in the diff (poc.available=false). Conceptually identical to 60126f0149: attacker SVG must make painting a re-enter resource resolution and clear pattern_map_ during BuildPatternData, so the pre-fix held reference dangles and the paint_flags write hits freed heap. Web-facing (rendering SVG suffices, no permissions). The exact invalidation chain is inferred from the commit message, not shown in the diff.
Exploitation
- Reach the sink (inferred) — Render SVG filling an element with url(#pattern) so LayoutSVGResourcePattern takes the pre-fix reference into pattern_map_ on the M150 build.
- Clear the map mid-build (inferred) — Pattern content triggers SVG resource invalidation that clears/rehashes pattern_map_ during BuildPatternData, freeing the referenced slot.
- UAF write (inferred) — Assignment through the dangling std::unique_ptr& and pattern_data->paint_flags = paint_flags write into freed heap — a UAF write in the renderer.
- Escalation (inferred) — Reclaiming and controlling the freed PatternData to build a stronger primitive is not demonstrated by the patch and is inferred.
Detection & hunting
For defenders and detection engineers:
- ASAN/UAF crashes in LayoutSVGResourcePattern —
- CHECK(pattern_data) abort —
- Re-entrant pattern_map_ mutation during BuildPatternData —
Audit directions
- Branch-coverage of the same fix —
- References/iterators held across re-entrant SVG builds —
- insert().stored_value->value usage —