Chrome · Paint
CVE-2026-113280
Memory Corruption in Paint
Overview
Critical
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Changed Functions
| Function | Change | Notes |
|---|---|---|
TEST_Fthird_party/blink/renderer/core/editing/frame_selection_test.cc |
modified |
Files Changed
third_party/blink/renderer/platform/runtime_enabled_features.json5third_party/blink/renderer/core/editing/frame_selection_test.ccthird_party/blink/renderer/core/editing/frame_caret.cc
Patch
From 3ab9f85874d939e29f1179d7184e79f3cdc58a47 Mon Sep 17 00:00:00 2001 From: Kent Tamura <[email protected]> Date: Wed, 07 Oct 2026 18:00:46 -0700 Subject: [PATCH] Remove redundant IsHidden() check in FrameCaret::PaintCaret() FrameCaret::PaintCaret() called FrameSelection::IsHidden(), which calls FrameSelection::SelectionHasFocus() and synchronously invokes Document::UpdateStyleAndLayout(). When FrameCaret::PaintCaret() is reached during PrePaintTreeWalk (for example, via an SVG <feImage> filter painting a subtree with a caret), re-entering style and layout can rebuild physical fragments while PrePaintTreeWalk is iterating over them. Checking FrameSelection::IsHidden() in FrameCaret::PaintCaret() is unnecessary: - For a caret (non-range selection), FrameSelection::IsHidden() is equivalent to !FrameSelection::SelectionHasFocus(). - At the end of layout, FrameCaret::UpdateStyleAndLayoutIfNeeded() calls FrameCaret::UpdateAppearance(), which checks FrameCaret::ShouldShowCaret() (including FrameSelection::SelectionHasFocus()). - If ShouldShowCaret() returns false, UpdateAppearance() returns a null position and CaretDisplayItemClient::UpdateStyleAndLayoutIfNeeded() clears `layout_block_`. - FrameCaret::PaintCaret() is only called when `layout_block_` is non-null, so SelectionHasFocus() is already guaranteed to be true, and CaretDisplayItemClient::PaintCaret() right above RecordSelection() already paints the caret unconditionally. Remove the redundant IsHidden() check and call CaretDisplayItemClient::RecordSelection() unconditionally in FrameCaret::PaintCaret(). Bug: 570740320 Change-Id: Id7e18c4fc26d8dcd35ba558046d164c0ad47b3b1 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8523219 Reviewed-by: Philip Rogers <[email protected]> Auto-Submit: Kent Tamura <[email protected]> Reviewed-by: Xianzhu Wang <[email protected]> Commit-Queue: Kent Tamura <[email protected]> Cr-Commit-Position: refs/heads/main@{#1714054} --- diff --git a/third_party/blink/renderer/core/editing/frame_caret.cc b/third_party/blink/renderer/core/editing/frame_caret.cc index c54a4a8..1a6f49ac 100644 --- a/third_party/blink/renderer/core/editing/frame_caret.cc +++ b/third_party/blink/renderer/core/editing/frame_caret.cc @@ -308,7 +308,8 @@ display_item_client_->PaintCaret(context, paint_offset, DisplayItem::kCaret); - if (!frame_->Selection().IsHidden()) { + if (RuntimeEnabledFeatures::FrameCaretSkipHiddenCheckEnabled() || + !frame_->Selection().IsHidden()) { auto type = frame_->Selection().IsHandleVisible() ? gfx::SelectionBound::Type::CENTER : gfx::SelectionBound::Type::HIDDEN; diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5 index 0bfd8fb..b063be9 100644 --- a/third_party/blink/renderer/platform/runtime_enabled_features.json5 +++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5 @@ -3473,6 +3473,11 @@ name: "FragmentedOofInCb", }, { + // crbug.com/570740320 + name: "FrameCaretSkipHiddenCheck", + status: "stable", + }, + { name: "FrameSerializerNoWebEntities", status: "stable", }, diff --git a/third_party/blink/renderer/core/editing/frame_selection_test.cc b/third_party/blink/renderer/core/editing/frame_selection_test.cc index fe7f9f3..a908544 100644 --- a/third_party/blink/renderer/core/editing/frame_selection_test.cc +++ b/third_party/blink/renderer/core/editing/frame_selection_test.cc @@ -1575,6 +1575,35 @@ EXPECT_EQ(gfx::SelectionBound::HIDDEN, selection_data->end->type); } +// crbug.com/570740320 +TEST_F(FrameSelectionTest, PaintCaretDoesNotUpdateStyleAndLayout) { + Text* text = AppendTextNode("Hello, World!"); + UpdateAllLifecyclePhasesForTest(); + + GetDocument().body()->setContentEditable("true", ASSERT_NO_EXCEPTION); + GetDocument().body()->Focus(); + Selection().SetCaretEnabled(true); + Selection().SetSelection( + SelectionInDomTree::Builder().Collapse(Position(text, 0)).Build(), + SetSelectionOptions()); + UpdateAllLifecyclePhasesForTest(); + ASSERT_TRUE(Selection().ShouldPaintCaret( + *To<LayoutBlock>(GetDocument().body()->GetLayoutObject()))); + + GetDocument().body()->SetInlineStyleProperty(CSSPropertyID::kColor, "red"); + ASSERT_TRUE(GetDocument().NeedsLayoutTreeUpdate()); + + PaintController paint_controller; + { + GraphicsContext context(paint_controller); + paint_controller.UpdateCurrentPaintChunkProperties( + root_paint_chunk_id_, *root_paint_property_client_, + PropertyTreeState::Root()); + Selection().PaintCaret(context, PhysicalOffset()); + } + EXPECT_TRUE(GetDocument().NeedsLayoutTreeUpdate()); +} + // =========================================================================== // Bidi state persistence in FrameSelection::Modify() // Tests the affinity override branch that adjusts selection affinity
Loading diff…
Regression Test / PoC
shipped with the fix
diff --git a/third_party/blink/renderer/core/editing/frame_selection_test.cc b/third_party/blink/renderer/core/editing/frame_selection_test.cc
index fe7f9f3..a908544 100644
--- a/third_party/blink/renderer/core/editing/frame_selection_test.cc
+++ b/third_party/blink/renderer/core/editing/frame_selection_test.cc
@@ -1575,6 +1575,35 @@
EXPECT_EQ(gfx::SelectionBound::HIDDEN, selection_data->end->type);
}
+// crbug.com/570740320
+TEST_F(FrameSelectionTest, PaintCaretDoesNotUpdateStyleAndLayout) {
+ Text* text = AppendTextNode("Hello, World!");
+ UpdateAllLifecyclePhasesForTest();
+
+ GetDocument().body()->setContentEditable("true", ASSERT_NO_EXCEPTION);
+ GetDocument().body()->Focus();
+ Selection().SetCaretEnabled(true);
+ Selection().SetSelection(
+ SelectionInDomTree::Builder().Collapse(Position(text, 0)).Build(),
+ SetSelectionOptions());
+ UpdateAllLifecyclePhasesForTest();
+ ASSERT_TRUE(Selection().ShouldPaintCaret(
+ *To<LayoutBlock>(GetDocument().body()->GetLayoutObject())));
+
+ GetDocument().body()->SetInlineStyleProperty(CSSPropertyID::kColor, "red");
+ ASSERT_TRUE(GetDocument().NeedsLayoutTreeUpdate());
+
+ PaintController paint_controller;
+ {
+ GraphicsContext context(paint_controller);
+ paint_controller.UpdateCurrentPaintChunkProperties(
+ root_paint_chunk_id_, *root_paint_property_client_,
+ PropertyTreeState::Root());
+ Selection().PaintCaret(context, PhysicalOffset());
+ }
+ EXPECT_TRUE(GetDocument().NeedsLayoutTreeUpdate());
+}
+
// ===========================================================================
// Bidi state persistence in FrameSelection::Modify()
// Tests the affinity override branch that adjusts selection affinity
Loading diff…
Original Bug Report
The reporter's bug is still restricted on the tracker. Chrome de-restricts security bugs ~30–90 days after the fix ships; a later run will backfill it here.
References
On This Page