Chrome · Compositing
CVE-2026-85051
Type Confusion in Compositing
Overview
High
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Changed Functions
| Function | Change | Notes |
|---|---|---|
ToScrollOffsetAnimationCurvecc/animation/scroll_offset_animation_curve.cc |
modified | |
TEST_Fcc/animation/scroll_timeline_unittest.cc |
modified |
Files Changed
cc/animation/animation_host.cccc/animation/filter_animation_curve.cccc/animation/scroll_offset_animation_curve.cccc/animation/scroll_timeline.hcc/animation/scroll_timeline_unittest.cccc/animation/timeline_trigger.cccc/animation/timeline_trigger.hcc/animation/worklet_animation.h
Patch
From deb41ddc5770bd74cc7d0e4d6a7d7b12e2c5ecec Mon Sep 17 00:00:00 2001 From: Robert Flack <[email protected]> Date: Fri, 28 Aug 2026 13:20:18 -0700 Subject: [PATCH] Promote DCHECK to CHECK in cc animation downcasts Promotes `DCHECK` downcast assertions to `CHECK` across `cc/animation/` downcasting helpers (`ToScrollTimeline`, `ToWorkletAnimation`, `ToScrollOffsetAnimationCurve`, and `ToFilterAnimationCurve`). Introduces `ToTimelineTrigger` helper functions with `CHECK` verification and uses them in `AnimationHost::UpdateTriggers`. This ensures downcasts between base and derived animation, timeline, trigger, and curve instances are always validated. Bug: 553449113 Change-Id: I06849cde7d144966b89ec2899eebef5f5a66fee0 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8308916 Reviewed-by: David A <[email protected]> Commit-Queue: Robert Flack <[email protected]> Cr-Commit-Position: refs/heads/main@{#1688263} --- diff --git a/cc/animation/animation_host.cc b/cc/animation/animation_host.cc index 0a5e0d6..8514063 100644 --- a/cc/animation/animation_host.cc +++ b/cc/animation/animation_host.cc @@ -1091,9 +1091,7 @@ for (const auto& kv : id_to_trigger_map_.Read(*this)) { AnimationTrigger* trigger = kv.second.get(); // NOTE(crbug.com/451238244): Only timeline triggers are supported for now. - DCHECK(trigger->IsTimelineTrigger()); - static_cast<TimelineTrigger*>(trigger)->Update(scroll_tree, events, - monotonic_time); + ToTimelineTrigger(trigger)->Update(scroll_tree, events, monotonic_time); } } diff --git a/cc/animation/filter_animation_curve.cc b/cc/animation/filter_animation_curve.cc index 8a01901f..003a1f43a 100644 --- a/cc/animation/filter_animation_curve.cc +++ b/cc/animation/filter_animation_curve.cc @@ -4,6 +4,7 @@ #include "cc/animation/filter_animation_curve.h" +#include "base/check_op.h" #include "base/memory/ptr_util.h" #include "ui/gfx/animation/keyframe/keyframed_animation_curve-inl.h" @@ -30,13 +31,13 @@ const FilterAnimationCurve* FilterAnimationCurve::ToFilterAnimationCurve( const gfx::AnimationCurve* c) { - DCHECK_EQ(gfx::AnimationCurve::FILTER, c->Type()); + CHECK_EQ(gfx::AnimationCurve::FILTER, c->Type()); return static_cast<const FilterAnimationCurve*>(c); } FilterAnimationCurve* FilterAnimationCurve::ToFilterAnimationCurve( gfx::AnimationCurve* c) { - DCHECK_EQ(AnimationCurve::FILTER, c->Type()); + CHECK_EQ(AnimationCurve::FILTER, c->Type()); return static_cast<FilterAnimationCurve*>(c); } diff --git a/cc/animation/scroll_offset_animation_curve.cc b/cc/animation/scroll_offset_animation_curve.cc index f2d5475..3e57ae3 100644 --- a/cc/animation/scroll_offset_animation_curve.cc +++ b/cc/animation/scroll_offset_animation_curve.cc @@ -412,13 +412,13 @@ const ScrollOffsetAnimationCurve* ScrollOffsetAnimationCurve::ToScrollOffsetAnimationCurve( const AnimationCurve* c) { - DCHECK_EQ(ScrollOffsetAnimationCurve::SCROLL_OFFSET, c->Type()); + CHECK_EQ(ScrollOffsetAnimationCurve::SCROLL_OFFSET, c->Type()); return static_cast<const ScrollOffsetAnimationCurve*>(c); } ScrollOffsetAnimationCurve* ScrollOffsetAnimationCurve::ToScrollOffsetAnimationCurve(AnimationCurve* c) { - DCHECK_EQ(ScrollOffsetAnimationCurve::SCROLL_OFFSET, c->Type()); + CHECK_EQ(ScrollOffsetAnimationCurve::SCROLL_OFFSET, c->Type()); return static_cast<ScrollOffsetAnimationCurve*>(c); } diff --git a/cc/animation/scroll_timeline.h b/cc/animation/scroll_timeline.h index 8d350fc..d6218ad 100644 --- a/cc/animation/scroll_timeline.h +++ b/cc/animation/scroll_timeline.h @@ -8,6 +8,7 @@ #include <optional> #include <vector> +#include "base/check.h" #include "base/time/time.h" #include "cc/animation/animation_export.h" #include "cc/animation/animation_timeline.h" @@ -199,13 +200,13 @@ }; inline ScrollTimeline* ToScrollTimeline(AnimationTimeline* timeline) { - DCHECK(timeline->IsScrollTimeline()); + CHECK(timeline->IsScrollTimeline()); return static_cast<ScrollTimeline*>(timeline); } inline const ScrollTimeline* ToScrollTimeline( const AnimationTimeline* timeline) { - DCHECK(timeline->IsScrollTimeline()); + CHECK(timeline->IsScrollTimeline()); return static_cast<const ScrollTimeline*>(timeline); } diff --git a/cc/animation/scroll_timeline_unittest.cc b/cc/animation/scroll_timeline_unittest.cc index 9824011f..d06aad59 100644 --- a/cc/animation/scroll_timeline_unittest.cc +++ b/cc/animation/scroll_timeline_unittest.cc @@ -437,4 +437,22 @@ active_timeline->IsActive(scroll_tree(), true /*is_active_tree*/)); } +TEST_F(ScrollTimelineTest, ToScrollTimeline) { + ScrollTimeline::ScrollOffsets scroll_offsets(0, 100); + scoped_refptr<ScrollTimeline> scroll_timeline = ScrollTimeline::Create( + scroller_id(), ScrollTimeline::ScrollDown, scroll_offsets); + scoped_refptr<AnimationTimeline> plain_timeline = + AnimationTimeline::Create(1); + + EXPECT_EQ(ToScrollTimeline(scroll_timeline.get()), scroll_timeline.get()); + const AnimationTimeline* const_scroll_timeline = scroll_timeline.get(); + EXPECT_EQ(ToScrollTimeline(const_scroll_timeline), scroll_timeline.get()); + +#if GTEST_HAS_DEATH_TEST + EXPECT_DEATH_IF_SUPPORTED(ToScrollTimeline(plain_timeline.get()), ""); + const AnimationTimeline* const_plain_timeline = plain_timeline.get(); + EXPECT_DEATH_IF_SUPPORTED(ToScrollTimeline(const_plain_timeline), ""); +#endif +} + } // namespace cc diff --git a/cc/animation/timeline_trigger.cc b/cc/animation/timeline_trigger.cc index c1c915ba..bc770f2 100644 --- a/cc/animation/timeline_trigger.cc +++ b/cc/animation/timeline_trigger.cc @@ -68,8 +68,7 @@ AnimationEvents* events, base::TimeTicks monotonic_time) { ScrollTimeline* scroll_timeline = - reinterpret_cast<ScrollTimeline*>(timeline_.Read(*this).get()); - DCHECK(scroll_timeline); + ToScrollTimeline(timeline_.Read(*this).get()); // Triggers only function based on the active tree. if (!scroll_timeline->IsActive(scroll_tree, /*is_active_tree=*/true)) { diff --git a/cc/animation/timeline_trigger.h b/cc/animation/timeline_trigger.h index 13a0203..5674704 100644 --- a/cc/animation/timeline_trigger.h +++ b/cc/animation/timeline_trigger.h @@ -5,6 +5,7 @@ #ifndef CC_ANIMATION_TIMELINE_TRIGGER_H_ #define CC_ANIMATION_TIMELINE_TRIGGER_H_ +#include "base/check.h" #include "cc/animation/animation_trigger.h" namespace cc { @@ -71,6 +72,17 @@ State state_ = State::kIdle; }; +inline TimelineTrigger* ToTimelineTrigger(AnimationTrigger* trigger) { + CHECK(trigger->IsTimelineTrigger()); + return static_cast<TimelineTrigger*>(trigger); +} + +inline const TimelineTrigger* ToTimelineTrigger( + const AnimationTrigger* trigger) { + CHECK(trigger->IsTimelineTrigger()); + return static_cast<const TimelineTrigger*>(trigger); +} + } // namespace cc #endif // CC_ANIMATION_TIMELINE_TRIGGER_H_ diff --git a/cc/animation/worklet_animation.h b/cc/animation/worklet_animation.h index e4323e7..1b4c5e4 100644 --- a/cc/animation/worklet_animation.h +++ b/cc/animation/worklet_animation.h @@ -9,6 +9,7 @@ #include <optional> #include <string> +#include "base/check.h" #include "base/time/time.h" #include "cc/animation/animation.h" #include "cc/animation/animation_export.h" @@ -154,10 +155,15 @@ }; inline WorkletAnimation* ToWorkletAnimation(Animation* animation) {
Loading diff…
Regression Test / PoC
shipped with the fix
diff --git a/cc/animation/scroll_timeline_unittest.cc b/cc/animation/scroll_timeline_unittest.cc
index 9824011f..d06aad59 100644
--- a/cc/animation/scroll_timeline_unittest.cc
+++ b/cc/animation/scroll_timeline_unittest.cc
@@ -437,4 +437,22 @@
active_timeline->IsActive(scroll_tree(), true /*is_active_tree*/));
}
+TEST_F(ScrollTimelineTest, ToScrollTimeline) {
+ ScrollTimeline::ScrollOffsets scroll_offsets(0, 100);
+ scoped_refptr<ScrollTimeline> scroll_timeline = ScrollTimeline::Create(
+ scroller_id(), ScrollTimeline::ScrollDown, scroll_offsets);
+ scoped_refptr<AnimationTimeline> plain_timeline =
+ AnimationTimeline::Create(1);
+
+ EXPECT_EQ(ToScrollTimeline(scroll_timeline.get()), scroll_timeline.get());
+ const AnimationTimeline* const_scroll_timeline = scroll_timeline.get();
+ EXPECT_EQ(ToScrollTimeline(const_scroll_timeline), scroll_timeline.get());
+
+#if GTEST_HAS_DEATH_TEST
+ EXPECT_DEATH_IF_SUPPORTED(ToScrollTimeline(plain_timeline.get()), "");
+ const AnimationTimeline* const_plain_timeline = plain_timeline.get();
+ EXPECT_DEATH_IF_SUPPORTED(ToScrollTimeline(const_plain_timeline), "");
+#endif
+}
+
} // namespace cc
diff --git a/cc/animation/worklet_animation_unittest.cc b/cc/animation/worklet_animation_unittest.cc
index 61ec54e5..bdd8c16 100644
--- a/cc/animation/worklet_animation_unittest.cc
+++ b/cc/animation/worklet_animation_unittest.cc
@@ -548,6 +548,26 @@
EXPECT_EQ(input->updated_animations.size(), 1u);
}
+TEST_F(WorkletAnimationTest, ToWorkletAnimation) {
+ scoped_refptr<WorkletAnimation> worklet_animation =
+ WorkletAnimation::Create(worklet_animation_id_, "test_name", 1.0,
+ /* options */ nullptr,
+ /* effect_timings */ nullptr);
+ scoped_refptr<Animation> plain_animation = Animation::Create(1);
+
+ EXPECT_EQ(ToWorkletAnimation(worklet_animation.get()),
+ worklet_animation.get());
+ const Animation* const_worklet_animation = worklet_animation.get();
+ EXPECT_EQ(ToWorkletAnimation(const_worklet_animation),
+ worklet_animation.get());
+
+#if GTEST_HAS_DEATH_TEST
+ EXPECT_DEATH_IF_SUPPORTED(ToWorkletAnimation(plain_animation.get()), "");
+ const Animation* const_plain_animation = plain_animation.get();
+ EXPECT_DEATH_IF_SUPPORTED(ToWorkletAnimation(const_plain_animation), "");
+#endif
+}
+
} // namespace
} // namespace cc
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