CVE-2026-103622
Overview
Changed Functions
| Function | Change | Notes |
|---|---|---|
ifthird_party/blink/renderer/core/layout/svg/layout_svg_resource_pattern.cc |
modified |
Files Changed
third_party/blink/renderer/core/layout/svg/layout_svg_resource_pattern.cc
Patch
From dedbd3f9dee8a579418b56c9a37c643873aafe1c Mon Sep 17 00:00:00 2001
From: Stefan Zager <szager@chromium.org>
Date: Mon, 28 Sep 2026 17:24:58 -0700
Subject: [PATCH] Reinsert PatternData into pattern map after reconstruction
LayoutSVGResourcePattern::pattern_map_ can be cleared while executing
BuildPatternData, so be sure it reinsert the newly-created pattern
data rather than using the (possibly stale) previous hash table
AddResult.
Fixed: 565742179
Change-Id: Iad113e3101920adf4b56da4805b4a46ebf681730
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8464440
Reviewed-by: Fredrik Söderquist <fs@opera.com>
Commit-Queue: Stefan Zager <szager@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1706535}
---
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_resource_pattern.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_resource_pattern.cc
index a482c01..86b0498 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_resource_pattern.cc
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_resource_pattern.cc
@@ -192,14 +192,18 @@
NOT_DESTROYED();
ClearInvalidationMask();
- std::unique_ptr<PatternData>& pattern_data =
- pattern_map_.insert(&client, nullptr).stored_value->value;
+ 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.reset();
+ pattern_data = nullptr;
}
if (!pattern_data) {
- pattern_data = BuildPatternData(reference_box, paint_flags);
+ 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;
}
Original Bug Report
Use-after-free in blink::LayoutSVGResourcePattern::ApplyShader
Summary
LayoutSVGResourcePattern::ApplyShader() holds a reference into pattern_map_’s backing store while BuildPatternData() paints the pattern’s content. A CSS Paint Worklet paint() callback that runs on the main thread during that paint can call registerPaint(), which synchronously invalidates the pattern and frees the backing. ApplyShader() then uses the stale reference. Renderer process, zero interaction.
Environment
- Chrome for Testing 154.0.8037.57 (Stable), 155.0.8059.12 (Beta), 156.0.8072.0 (Canary); code unchanged on main b7c07f35773a
- Ubuntu 24.04, x86-64
- Evidence build: ASan, Chromium 155.0.8038.0
Reproduction
chrome --user-data-dir=/tmp/p --no-first-run poc.html
- Launch with a fresh profile.
- Wait; zero interaction beyond loading the page. The renderer crashes after about 3 s.
Rate: Stable 4/4, Beta 3/3, Canary 4/4.
Evidence
Renderer, main thread. Full reports: asan.txt, asan-dcheck.txt (DCHECK build, same bug, no DCHECK fires).
use-after-poison READ of size 8
#0 LayoutSVGResourcePattern::ApplyShader
#1 SVGObjectPainter::PreparePaint svg_object_painter.cc:41
freed (Oilpan): LayoutSVGResourcePattern::RemoveAllClientsFromCache
<- LayoutSVGImage::ImageChanged <- CSSPaintValue::Observer::PaintImageGeneratorReady
<- PaintWorklet::RegisterCSSPaintDefinition <- PaintWorkletGlobalScope::registerPaint
Vulnerable code
third_party/blink/renderer/core/layout/svg/layout_svg_resource_pattern.cc
64 pattern_map_.clear(); [3]
195 std::unique_ptr<PatternData>& pattern_data =
196 pattern_map_.insert(&client, nullptr).stored_value->value; [1]
202 pattern_data = BuildPatternData(reference_box, paint_flags); [2]
[1] Reference into the HeapHashMap backing. [2] Paints the pattern’s children, then assigns through that reference. If a child’s paint reaches [3], the backing is freed while [1] is live.
Impact
Any web page in a secure context, no interaction. Renderer use-after-free. Reporter’s estimate: High (S1).
Discovery and validation
Found by AI-assisted source review and dynamic testing (Claude).
Attachments: poc.html, asan.txt, asan-dcheck.txt, report.md (full write-up)