Critical chrome Memory Corruption 🔧 Commit mapped

Overview

Critical
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactMemory corruption in Paint
DescriptionMemory corruption in Paint
ComponentPaint
Bug ClassMemory Corruption
Tracker570740320
Fix commit3ab9f85874d9 (chromium/src) +36/-1
CISA KEVNot listed
CreditedXinyang Ge
Disclosed2026-10-20

Changed Functions

FunctionChangeNotes
TEST_F
third_party/blink/renderer/core/editing/frame_selection_test.cc
modified

Files Changed

  • third_party/blink/renderer/platform/runtime_enabled_features.json5
  • third_party/blink/renderer/core/editing/frame_selection_test.cc
  • third_party/blink/renderer/core/editing/frame_caret.cc
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.