Medium CVSS 8.8 chrome UAF 📄 Reporter bug report 🔧 Commit mapped

Overview

Medium
Severity
8.8
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactUse after free in Views
DescriptionUse after free in Views
ComponentViews
Sub-componentOzone/X11
Bug ClassUAF
Tracker524825209
Fix commit17bd32efbc79 (chromium/src) +52/-0
Related commitsfc4613ff876d previously mapped (not the fix) · chromium/src
CWECWE-416 (Use-after-free)
CVSS vectorCVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
CISA KEVNot listed
CreditedGoogle
Reported2026-06-17 (per vendor advisory)
Fix landed2026-06-18 (public git)
Disclosed2026-07-29
Patch gap41 days — fix public in source before the advisory
Re-mapped on 2026-10-03: our pipeline had picked the earliest commit citing this bug (fc4613ff876d), which an audit found was a preparatory/helper change, not the fix. This page now points to the commit whose diff removes the bug. No root-cause analysis is published for this CVE.

Changed Functions

FunctionChangeNotes
if
ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc
modified
CenterWindowCloseWidgetScreen
ui/views/widget/desktop_aura/desktop_window_tree_host_platform_unittest.cc
modified
widget_
ui/views/widget/desktop_aura/desktop_window_tree_host_platform_unittest.cc
modified
if
ui/views/widget/desktop_aura/desktop_window_tree_host_platform_unittest.cc
modified

Files Changed

  • ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc
  • ui/views/widget/desktop_aura/desktop_window_tree_host_platform_unittest.cc
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc b/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc
index d538135..df187a5 100644
--- a/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc
+++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc
@@ -555,7 +555,11 @@
 }
 
 void DesktopWindowTreeHostPlatform::CenterWindow(const gfx::Size& size) {
+  auto weak_ptr = weak_factory_.GetWeakPtr();
   gfx::Rect parent_bounds = GetWorkAreaBoundsInScreen();
+  if (!weak_ptr) {
+    return;
+  }
 
   // If |window_|'s transient parent bounds are big enough to contain |size|,
   // use them instead.
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_platform_unittest.cc b/ui/views/widget/desktop_aura/desktop_window_tree_host_platform_unittest.cc
index 264680e..d255411 100644
--- a/ui/views/widget/desktop_aura/desktop_window_tree_host_platform_unittest.cc
+++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_platform_unittest.cc
@@ -23,6 +23,7 @@
 #include "ui/base/ui_base_features.h"
 #include "ui/compositor/layer.h"
 #include "ui/display/display_switches.h"
+#include "ui/display/test/test_screen.h"
 #include "ui/display/types/display_constants.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/native_ui_types.h"
@@ -855,6 +856,53 @@
   // This should not crash or trigger UAF.
   host_platform->Restore();
 }
+
+class CenterWindowCloseWidgetScreen : public display::test::TestScreen {
+ public:
+  explicit CenterWindowCloseWidgetScreen(Widget* widget)
+      : display::test::TestScreen(/*create_display=*/false,
+                                  /*register_screen=*/false),
+        widget_(widget) {
+    display_list().AddDisplay({0, gfx::Rect(0, 0, 800, 600)},
+                              display::DisplayList::Type::PRIMARY);
+    old_screen_ = display::Screen::SetScreenInstance(nullptr);
+    display::Screen::SetScreenInstance(this);
+  }
+
+  ~CenterWindowCloseWidgetScreen() override {
+    display::Screen::SetScreenInstance(nullptr);
+    display::Screen::SetScreenInstance(old_screen_);
+  }
+
+  display::Display GetDisplayNearestWindow(
+      gfx::NativeWindow window) const override {
+    if (widget_ && !widget_closed_) {
+      widget_closed_ = true;
+      widget_->CloseNow();
+    }
+    return display::test::TestScreen::GetDisplayNearestWindow(window);
+  }
+
+ private:
+  raw_ptr<Widget> widget_;
+  raw_ptr<display::Screen> old_screen_ = nullptr;
+  mutable bool widget_closed_ = false;
+};
+
+TEST_F(DesktopWindowTreeHostPlatformTest,
+       CenterWindowSurvivesSynchronousClose) {
+  std::unique_ptr<Widget> widget = CreateWidgetWithNativeWidget();
+  widget->Show();
+
+  auto* host_platform = DesktopWindowTreeHostPlatform::GetHostForWidget(
+      widget->GetNativeWindow()->GetHost()->GetAcceleratedWidget());
+  ASSERT_TRUE(host_platform);
+
+  CenterWindowCloseWidgetScreen test_screen(widget.get());
+
+  // This should not crash or trigger UAF.
+  host_platform->CenterWindow(gfx::Size(100, 100));
+}
 #endif  // !BUILDFLAG(IS_FUCHSIA)
 
 }  // namespace views
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_platform_unittest.cc b/ui/views/widget/desktop_aura/desktop_window_tree_host_platform_unittest.cc
index 264680e..d255411 100644
--- a/ui/views/widget/desktop_aura/desktop_window_tree_host_platform_unittest.cc
+++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_platform_unittest.cc
@@ -23,6 +23,7 @@
 #include "ui/base/ui_base_features.h"
 #include "ui/compositor/layer.h"
 #include "ui/display/display_switches.h"
+#include "ui/display/test/test_screen.h"
 #include "ui/display/types/display_constants.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/native_ui_types.h"
@@ -855,6 +856,53 @@
   // This should not crash or trigger UAF.
   host_platform->Restore();
 }
+
+class CenterWindowCloseWidgetScreen : public display::test::TestScreen {
+ public:
+  explicit CenterWindowCloseWidgetScreen(Widget* widget)
+      : display::test::TestScreen(/*create_display=*/false,
+                                  /*register_screen=*/false),
+        widget_(widget) {
+    display_list().AddDisplay({0, gfx::Rect(0, 0, 800, 600)},
+                              display::DisplayList::Type::PRIMARY);
+    old_screen_ = display::Screen::SetScreenInstance(nullptr);
+    display::Screen::SetScreenInstance(this);
+  }
+
+  ~CenterWindowCloseWidgetScreen() override {
+    display::Screen::SetScreenInstance(nullptr);
+    display::Screen::SetScreenInstance(old_screen_);
+  }
+
+  display::Display GetDisplayNearestWindow(
+      gfx::NativeWindow window) const override {
+    if (widget_ && !widget_closed_) {
+      widget_closed_ = true;
+      widget_->CloseNow();
+    }
+    return display::test::TestScreen::GetDisplayNearestWindow(window);
+  }
+
+ private:
+  raw_ptr<Widget> widget_;
+  raw_ptr<display::Screen> old_screen_ = nullptr;
+  mutable bool widget_closed_ = false;
+};
+
+TEST_F(DesktopWindowTreeHostPlatformTest,
+       CenterWindowSurvivesSynchronousClose) {
+  std::unique_ptr<Widget> widget = CreateWidgetWithNativeWidget();
+  widget->Show();
+
+  auto* host_platform = DesktopWindowTreeHostPlatform::GetHostForWidget(
+      widget->GetNativeWindow()->GetHost()->GetAcceleratedWidget());
+  ASSERT_TRUE(host_platform);
+
+  CenterWindowCloseWidgetScreen test_screen(widget.get());
+
+  // This should not crash or trigger UAF.
+  host_platform->CenterWindow(gfx::Size(100, 100));
+}
 #endif  // !BUILDFLAG(IS_FUCHSIA)
 
 }  // namespace views
Loading diff…

Original Bug Report

reported by vm...@google.com

Potential Browser-Process UAF in DesktopWindowTreeHostPlatform::CenterWindow

Project Fortify, an experimental security project, has identified the following potential security issue. If you’re a feature owner CC-ed on this bug, please do your best to review these reports. Please see https://chromium.googlesource.com/chromium/src/+/main/docs/security/ai-generated-security-bugs-faq.md for more information.

Overview: A potential Use-After-Free (UAF) vulnerability exists in DesktopWindowTreeHostPlatform::CenterWindow on Linux/X11 (Ozone). Querying the work area bounds can transitively dispatch pending X11 events synchronously via GeometryCache, which can trigger host destruction. When execution resumes in CenterWindow, the code dereferences the freed host instance, potentially leading to a wild virtual function call.

Affected files:

  • ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc
  • ui/ozone/platform/x11/x11_screen_ozone.cc
  • ui/ozone/platform/x11/x11_window.cc

Estimated timestamp from git blame: 2025-03-06

Root Cause Analysis

In ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc, the function DesktopWindowTreeHostPlatform::CenterWindow executes the following sequence:

void DesktopWindowTreeHostPlatform::CenterWindow(const gfx::Size& size) {
  gfx::Rect parent_bounds = GetWorkAreaBoundsInScreen();   // <-- Potential synchronous deletion sink

  if (wm::GetTransientParent(GetContentWindow())) {        // <-- UAF read of freed |this|
    gfx::Rect transient_parent_rect =
        wm::GetTransientParent(GetContentWindow())->GetBoundsInScreen();
    ...
  }
  ...
  SetBoundsInDIP(window_bounds_in_screen);                 // <-- UAF virtual call on freed |this|
}

When GetWorkAreaBoundsInScreen() is called under Linux/Ozone/X11, it queries the display system which transitively invokes X11Window::GetBoundsInPixels().

If the window was recently created or reparented, the underlying GeometryCache may be un-Ready (i.e., waiting for responses from the X11 server). To resolve this, GeometryCache::GetBoundsPx() synchronously dispatches the pending futures via DispatchNow() to process incoming server replies. This runs the message loop synchronously.

Processing these events can trigger bounds-change notifications, causing registered WindowTreeHostObservers to run. If an observer synchronously closes the widget/host (e.g., during complex layout recalculations or window-snapping events), the DesktopWindowTreeHostPlatform instance is deleted via host_.reset(). When control returns to CenterWindow(), execution continues using the now-freed this pointer, causing a Use-After-Free read on desktop_native_widget_aura_ followed by a virtual method call on SetBoundsInDIP through a hijacked vtable pointer.

Potential Trigger Path

Note: The following are suggested/potential steps to trigger the behavior, as our tooling does not currently have the capability to run code to confirm live execution:

  1. From the renderer or browser UI, trigger the initialization of a top-level widget/dialog with default or empty bounds on Linux/X11.
  2. The window is initialized, and Widget::SetInitialBounds calls CenterWindow() before the X server has replied to the window geometry queries.
  3. The synchronous DispatchNow() loop is entered within GeometryCache::GetBoundsPx() to retrieve the geometry replies.
  4. An event handler or observer intercepts the bounds change and immediately calls Widget::CloseNow(), which synchronously deletes the DesktopWindowTreeHostPlatform host container.
  5. Control flow returns to CenterWindow(), resulting in a browser-process UAF.

MiraclePtr Status

This UAF is not protected by MiraclePtr. The dangling pointer is the implicit stack this pointer (not a raw_ptr<>). The member field desktop_native_widget_aura_ resides inside the freed DesktopWindowTreeHostPlatform allocation, so reading it is a UAF on the storage itself rather than a BRP-quarantined reference.

Suggested Fix

Add a base::WeakPtr guard in DesktopWindowTreeHostPlatform::CenterWindow to safely abort execution if the host is synchronously destroyed during the bounds query:

void DesktopWindowTreeHostPlatform::CenterWindow(const gfx::Size& size) {
  base::WeakPtr<DesktopWindowTreeHostPlatform> weak_this = weak_factory_.GetWeakPtr();
  gfx::Rect parent_bounds = GetWorkAreaBoundsInScreen();
  if (!weak_this) {
    return;
  }

  if (wm::GetTransientParent(GetContentWindow())) {
    ...

Evaluated with Chrome root at commit: 75203b87cbf6681eb7c7dda8e1d0bf781538c76a


Results so far have been promising, but there can be wrong deductions. Feel free to adjust as follows:

  • If you are familiar with the severity guidelines, you may adjust the severity.
  • If this is a false positive, and there’s no work to be done, please close as WAI.
  • If there is work to do here but not a vulnerability, please change the issue type to Task/Bug/FR.

Data from false positives will be used to improve accuracy over time. And please feel free to reach out to me directly if you have concerns or feedback on the project.

View on issue tracker