CVE-2026-79245
Overview
Background
- `WindowModalityController`
- a
ui/wmcomponent (window_modality_controller.cc) that observes window changes and enforces modal-dialog behavior, such as activating modal windows and canceling touches. - `aura::Window::ScopedDeleteBlocker`
- an RAII object that prevents an
aura::Windowfrom being destroyed while it remains in scope. - `kModalKey` property
- an
aura::clientwindow property whose value (ui::mojom::ModalType) marks a window as modal. - `ActivateWindow`
- an activation-client call that focuses/activates a window and can synchronously run observers that may destroy windows.
Root Cause Analysis
In the modality controller’s property-change handler, when a window’s kModalKey became non-kNone and the window was visible, the code called ActivateWindow(window) and then CancelTouchesOnTransientWindowTree(window) on the raw window pointer. ActivateWindow can synchronously dispatch activation/observer callbacks that delete window, after which continued use of window — within ActivateWindow itself or the following CancelTouchesOnTransientWindowTree(window) call — dereferences freed memory, a use-after-free. The invariant that window remains alive for the duration of the activation sequence was not guaranteed.
The fix constructs an aura::Window::ScopedDeleteBlocker blocker(window) before ActivateWindow, so any deletion attempt during activation is blocked until the blocker leaves scope, keeping window valid across both calls.
ActivateWindow; the fix pins the window alive with a ScopedDeleteBlocker for the whole activation sequence.Attack Path
- Trigger a modal property change
content causes a window’s
kModalKeyto be set to a non-kNoneModalTypewhile the window is visible, entering the vulnerable branch of the property-change handler. - Activate the window
the handler calls
ActivateWindow(window), which synchronously runs activation/observer callbacks. - Reentrant deletion
one of those callbacks destroys
windowduring activation (the exact deleter is(inferred)), freeing it mid-sequence. - Use freed window
execution continues and
CancelTouchesOnTransientWindowTree(window)(and/or remainingActivateWindowwork) dereferences the freedwindow, a use-after-free.
Impact Assessment
ui/wm) when a modal window is deleted reentrantly during activation, so an attacker able to drive modal-window property changes and a coincident deletion could operate on freed memory. Escalation to control-flow hijack or code execution is (inferred), and the advisory does not indicate in-the-wild exploitation.Files Changed
ui/wm/core/window_modality_controller.cc
Audit Directions
- Raw-pointer reuse across activation/focus callsaudit
ui/wmand aura handlers that keep using aWindow*after callingActivateWindow/Focus/observer-dispatching APIs that can reentrantly delete it. - Observer callbacks that delete their subjectreview property-change and event observers that operate on a window/object which downstream synchronous callbacks might destroy, and guard with
ScopedDeleteBlockeror weak pointers. - Reentrancy in modal/activation flowscheck other modal, transient-window, and activation transitions for sequences that dereference an object after a call capable of triggering nested teardown.
Patch
From 5fd08025f12a182600e17849cf6fe8d175dcd7f4 Mon Sep 17 00:00:00 2001
From: Achuith Bhandarkar <achuith@chromium.org>
Date: Wed, 22 Jul 2026 17:10:17 -0700
Subject: [PATCH] wm: Use ScopedDeleteBlocker in OnWindowPropertyChanged
`window` should not be deleted during ActivateWindow.
TAG=agy
CONV=45d56d3a-66eb-4f31-b43a-39b4009eabba
Bug: 520179360
Change-Id: I3cb6b8c20d2840f78a1f3e78c2801491a14bdc3b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7975659
Reviewed-by: Mitsuru Oshima <oshima@chromium.org>
Commit-Queue: Achuith Bhandarkar <achuith@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1666727}
---
diff --git a/ui/wm/core/window_modality_controller.cc b/ui/wm/core/window_modality_controller.cc
index 8204f350..2ff166e2 100644
--- a/ui/wm/core/window_modality_controller.cc
+++ b/ui/wm/core/window_modality_controller.cc
@@ -169,6 +169,8 @@
window->GetProperty(aura::client::kModalKey) !=
ui::mojom::ModalType::kNone &&
window->IsVisible()) {
+ // Block the deletion of `window`.
+ aura::Window::ScopedDeleteBlocker blocker(window);
ActivateWindow(window);
CancelTouchesOnTransientWindowTree(window);
}
Original Bug Report
Potential Crash in WindowModalityController::OnWindowPropertyChanged during Window Activation
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: An analysis of WindowModalityController::OnWindowPropertyChanged identified a potential re-entrancy path where ActivateWindow can trigger window destruction before CancelTouchesOnTransientWindowTree is called. However, investigation reveals that synchronous destruction under this path is intercepted by ScopedDeleteBlocker, resulting in a safe CHECK crash rather than a Use-After-Free. This report documents the re-entrancy flow and recommends a robust safety improvement.
Affected files:
ui/wm/core/window_modality_controller.cc
Estimated timestamp from git blame: 2018-11-14
Description
In ui/wm/core/window_modality_controller.cc:163-175, when the kModalKey property is modified on an already-visible window, WindowModalityController::OnWindowPropertyChanged is triggered:
void WindowModalityController::OnWindowPropertyChanged(aura::Window* window,
const void* key,
intptr_t old) {
if (key == aura::client::kModalKey &&
window->GetProperty(aura::client::kModalKey) !=
ui::mojom::ModalType::kNone &&
window->IsVisible()) {
ActivateWindow(window);
CancelTouchesOnTransientWindowTree(window);
}
}
Calling ActivateWindow(window) synchronously fires activation and deactivation observers via the focus/activation controller. If a deactivation or focus observer attempts to synchronously destroy the window, CancelTouchesOnTransientWindowTree(window) would immediately execute and dereference the potentially freed window pointer.
Root Cause & Existing Safety Mechanisms
An in-depth analysis of the Aura window lifetime management reveals that a Use-After-Free (UAF) is successfully prevented by the following safety barriers:
-
ScopedDeleteBlockerProtection: When a window property is changed,aura::Window::AfterPropertyChangeis executed. This function places aScopedDeleteBlockeron the stack, incrementing the window’sdelete_block_count_before notifying observers:void Window::AfterPropertyChange(const void* key, int64_t old_value) { ScopedDeleteBlocker blocker(this); for (WindowObserver& observer : observers_) observer.OnWindowPropertyChanged(this, key, old_value); }If any observer attempts to synchronously delete
window(or its transient parent/child which cascades towindow), the destructorWindow::~Window()executes the safety checkCHECK_EQ(delete_block_count_, 0u). Sincedelete_block_count_is non-zero, the browser process safely and immediately terminates with a crash, preventing any UAF condition. -
Asynchronous Exo Widget Destruction: For Wayland clients (Exo), widget destruction sequences (e.g., capture-loss or deactivation-triggered closes) use
Widget::Close(), which posts an asynchronous task to delete the widget. Thus, synchronous destruction of the native window cannot be initiated by Wayland client actions during activation observer dispatch. -
Transient Tree Integrity: If a transient parent window is destroyed under normal conditions, standard destruction observers cleanly update the active window’s parent pointers to
nullptr, ensuring no dangling references are left in the tree.
Potential Steps to Trigger the Safe Crash
An attacker/client could theoretically try to trigger a crash (Denial of Service) via the following suggested steps:
- From a Wayland client, create and commit an
xdg_toplevelwindow that is mapped and visible. - Configure focus such that activating this window deactivates another window containing an observer that initiates synchronous closure of the transient hierarchy.
- Request system modal state on the visible window via
zaura_toplevel.set_system_modalorzcr_remote_surface_v2.set_system_modal. - During
ActivateWindow, the synchronous deletion path is executed, immediately triggering a safe browser-process crash due to thedelete_block_count_assertion.
Suggested Fix
To make the code robust against re-entrancy hazards and avoid potential denial of service crashes, it is recommended to use aura::WindowTracker to check if the window is still alive after ActivateWindow completes:
void WindowModalityController::OnWindowPropertyChanged(aura::Window* window,
const void* key,
intptr_t old) {
if (key == aura::client::kModalKey &&
window->GetProperty(aura::client::kModalKey) !=
ui::mojom::ModalType::kNone &&
window->IsVisible()) {
aura::WindowTracker tracker({window});
ActivateWindow(window);
if (tracker.Contains(window)) {
CancelTouchesOnTransientWindowTree(window);
}
}
}
Evaluated with Chrome root at commit: d8b226a3be7c9c1ac9240c09e14698866c82e4ac
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.