Chrome · TopChrome
CVE-2026-7970
UAF in TopChrome
Overview
Medium
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Changed Functions
| Function | Change | Notes |
|---|---|---|
ifchrome/browser/ui/toasts/toast_view_browsertest.cc |
modified |
Files Changed
chrome/browser/ui/toasts/toast_controller.ccchrome/browser/ui/toasts/toast_view.ccchrome/browser/ui/toasts/toast_view.hchrome/browser/ui/toasts/toast_view_browsertest.cc
Patch
From 53245ff272a9b4118ed8129092263b23e012fdc3 Mon Sep 17 00:00:00 2001 From: Alison Gale <[email protected]> Date: Fri, 03 Apr 2026 17:47:23 -0700 Subject: [PATCH] Prevent UAF by storing ImageModel rather than raw_ptr Bug: 497487462 Change-Id: Ieb551cfcda46428c1569c355b1645b5cfa69cc56 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7729341 Reviewed-by: Steven Luong <[email protected]> Commit-Queue: Alison Gale <[email protected]> Cr-Commit-Position: refs/heads/main@{#1610045} --- diff --git a/chrome/browser/ui/toasts/toast_controller.cc b/chrome/browser/ui/toasts/toast_controller.cc index e8ee971a..1b41d0c8 100644 --- a/chrome/browser/ui/toasts/toast_controller.cc +++ b/chrome/browser/ui/toasts/toast_controller.cc @@ -302,10 +302,6 @@ return; } - const ui::ImageModel* image_override = params.image_override.has_value() - ? ¶ms.image_override.value() - : nullptr; - const std::u16string body_string = params.body_string_override.has_value() ? params.body_string_override.value() @@ -313,7 +309,7 @@ params.body_string_replacement_params, params.body_string_cardinality_param); auto toast_view = std::make_unique<toasts::ToastView>( - anchor_view, body_string, spec->icon(), image_override, + anchor_view, body_string, spec->icon(), params.image_override, ShouldRenderToastOverWebContents(), base::BindRepeating(&RecordToastDismissReason, params.toast_id)); diff --git a/chrome/browser/ui/toasts/toast_view.cc b/chrome/browser/ui/toasts/toast_view.cc index c43d4907..3d5ca1c4 100644 --- a/chrome/browser/ui/toasts/toast_view.cc +++ b/chrome/browser/ui/toasts/toast_view.cc @@ -56,9 +56,9 @@ return transform; } -bool IsCompatibleImageSize(const ui::ImageModel* image) { +bool IsCompatibleImageSize(const ui::ImageModel& image) { const auto intended_size = toasts::ToastView::GetIconSize(); - const auto image_size = image->Size(); + const auto image_size = image.Size(); return image_size.width() == intended_size && image_size.height() == intended_size; } @@ -106,14 +106,14 @@ views::View* anchor_view, const std::u16string& toast_text, const gfx::VectorIcon& icon, - const ui::ImageModel* image_override, + std::optional<ui::ImageModel> image_override, bool render_toast_over_web_contents, base::RepeatingCallback<void(ToastCloseReason)> toast_close_callback) : BubbleDialogDelegateView(anchor_view, views::BubbleBorder::NONE), AnimationDelegateViews(this), toast_text_(toast_text), icon_(icon), - image_override_(image_override), + image_override_(std::move(image_override)), render_toast_over_web_contents_(render_toast_over_web_contents), toast_close_callback_(std::move(toast_close_callback)) { SetBackgroundColor(ui::kColorToastBackgroundProminent); @@ -424,8 +424,9 @@ void ToastView::OnThemeChanged() { BubbleDialogDelegateView::OnThemeChanged(); const auto* color_provider = GetColorProvider(); - if (image_override_ != nullptr && IsCompatibleImageSize(image_override_)) { - icon_view_->SetImage(*image_override_); + if (image_override_.has_value() && + IsCompatibleImageSize(image_override_.value())) { + icon_view_->SetImage(image_override_.value()); } else { icon_view_->SetImage(ui::ImageModel::FromVectorIcon( *icon_, color_provider->GetColor(ui::kColorToastForeground), diff --git a/chrome/browser/ui/toasts/toast_view.h b/chrome/browser/ui/toasts/toast_view.h index 0f5074b6..3f11d0a 100644 --- a/chrome/browser/ui/toasts/toast_view.h +++ b/chrome/browser/ui/toasts/toast_view.h @@ -60,7 +60,7 @@ views::View* anchor_view, const std::u16string& toast_text, const gfx::VectorIcon& icon, - const ui::ImageModel* image_override, + std::optional<ui::ImageModel> image_override, bool should_hide_ui_for_fullscreen, base::RepeatingCallback<void(ToastCloseReason)> on_toast_close_callback); ~ToastView() override; @@ -124,7 +124,7 @@ const std::u16string toast_text_; const raw_ref<const gfx::VectorIcon> icon_; - const raw_ptr<const ui::ImageModel> image_override_; + const std::optional<ui::ImageModel> image_override_; bool render_toast_over_web_contents_; bool has_close_button_ = false; bool has_action_button_ = false; diff --git a/chrome/browser/ui/toasts/toast_view_browsertest.cc b/chrome/browser/ui/toasts/toast_view_browsertest.cc index d290db84..ab106f90 100644 --- a/chrome/browser/ui/toasts/toast_view_browsertest.cc +++ b/chrome/browser/ui/toasts/toast_view_browsertest.cc @@ -52,16 +52,16 @@ if (!options_.text.empty()) { toast_text = options_.text; } + std::optional<ui::ImageModel> image_override; if (options_.add_image_override) { int size = toasts::ToastView::GetIconSize(); - image_override_ = - std::make_unique<ui::ImageModel>(ui::ImageModel::FromImage( - gfx::test::CreateImage(size, size, 0xff0000))); + image_override = ui::ImageModel::FromImage( + gfx::test::CreateImage(size, size, 0xff0000)); } std::unique_ptr<toasts::ToastView> toast = std::make_unique<toasts::ToastView>( anchor_view_, toast_text, vector_icons::kLinkIcon, - image_override_.get(), false, base::DoNothing()); + std::move(image_override), false, base::DoNothing()); if (options_.add_close_button) { toast->AddCloseButton(base::DoNothing()); } @@ -99,7 +99,6 @@ private: raw_ptr<views::View> anchor_view_; - std::unique_ptr<ui::ImageModel> image_override_; raw_ptr<toasts::ToastView> toast_; raw_ptr<views::Widget> widget_; ToastOptions options_;
Loading diff…
Regression Test / PoC
shipped with the fix
diff --git a/chrome/browser/ui/toasts/toast_view_browsertest.cc b/chrome/browser/ui/toasts/toast_view_browsertest.cc
index d290db84..ab106f90 100644
--- a/chrome/browser/ui/toasts/toast_view_browsertest.cc
+++ b/chrome/browser/ui/toasts/toast_view_browsertest.cc
@@ -52,16 +52,16 @@
if (!options_.text.empty()) {
toast_text = options_.text;
}
+ std::optional<ui::ImageModel> image_override;
if (options_.add_image_override) {
int size = toasts::ToastView::GetIconSize();
- image_override_ =
- std::make_unique<ui::ImageModel>(ui::ImageModel::FromImage(
- gfx::test::CreateImage(size, size, 0xff0000)));
+ image_override = ui::ImageModel::FromImage(
+ gfx::test::CreateImage(size, size, 0xff0000));
}
std::unique_ptr<toasts::ToastView> toast =
std::make_unique<toasts::ToastView>(
anchor_view_, toast_text, vector_icons::kLinkIcon,
- image_override_.get(), false, base::DoNothing());
+ std::move(image_override), false, base::DoNothing());
if (options_.add_close_button) {
toast->AddCloseButton(base::DoNothing());
}
@@ -99,7 +99,6 @@
private:
raw_ptr<views::View> anchor_view_;
- std::unique_ptr<ui::ImageModel> image_override_;
raw_ptr<toasts::ToastView> toast_;
raw_ptr<views::Widget> widget_;
ToastOptions options_;
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