Skip to content

Commit 737a0c6

Browse files
fangzhougmibrunin
authored andcommitted
[Backport] CVE-2025-12438: Use after free in Ozone
Manual cherry-pick of patch originally reviewed on https://chromium-review.googlesource.com/c/chromium/src/+/6979565: Remove idle_inhibitor_ object from WaylandScreen ..to prevent UAF on chrome shutdown. Unlike most objects created by WaylandConnection, WaylandScreen is owned by ChromeBrowserMainExtraParts and outlives WaylandConnection. To prevent accessing wl_display internals after destruction of WaylandConnection, WaylandScreen should either destroy wl::Object when connection resets, or reference wl::Object indirectly. Manage inhibitor in zwp_idle_inhibit_manager. Also fix a logic in IsScreenSaverActive() where `inhibitor` mean screen saver is blocked. Bug: 433027577, 433643249 Change-Id: If02755ddced08f8cf795ac21ed144387d0aa4077 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6979565 Commit-Queue: Kramer Ge <[email protected]> Reviewed-by: Thomas Anderson <[email protected]> Cr-Commit-Position: refs/heads/main@{#1520174} Reviewed-on: https://codereview.qt-project.org/c/qt/qtwebengine-chromium/+/689570 Reviewed-by: Michal Klocek <[email protected]>
1 parent 01924ef commit 737a0c6

File tree

4 files changed

+49
-26
lines changed

4 files changed

+49
-26
lines changed

chromium/ui/ozone/platform/wayland/host/wayland_screen.cc

Lines changed: 6 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -433,31 +433,19 @@ bool WaylandScreen::SetScreenSaverSuspended(bool suspend) {
433433
return false;
434434

435435
if (suspend) {
436-
// Wayland inhibits idle behaviour on certain output, and implies that a
437-
// surface bound to that output should obtain the inhibitor and hold it
438-
// until it no longer needs to prevent the output to go idle.
439-
// We assume that the idle lock is initiated by the user, and therefore the
440-
// surface that we should use is the one owned by the window that is focused
441-
// currently.
442-
const auto* window_manager = connection_->window_manager();
443-
DCHECK(window_manager);
444-
const auto* current_window = window_manager->GetCurrentFocusedWindow();
445-
if (!current_window) {
446-
LOG(WARNING) << "Cannot inhibit going idle when no window is focused";
447-
return false;
448-
}
449-
DCHECK(current_window->root_surface());
450-
idle_inhibitor_ = connection_->zwp_idle_inhibit_manager()->CreateInhibitor(
451-
current_window->root_surface()->surface());
436+
connection_->zwp_idle_inhibit_manager()->CreateInhibitor();
452437
} else {
453-
idle_inhibitor_.reset();
438+
connection_->zwp_idle_inhibit_manager()->RemoveInhibitor();
454439
}
455440

456441
return true;
457442
}
458443

459444
bool WaylandScreen::IsScreenSaverActive() const {
460-
return idle_inhibitor_ != nullptr;
445+
// idle_inhibitor prevents screen saver from engaging, but does not indicate
446+
// whether screen saver is active or not. Assume not here.
447+
NOTIMPLEMENTED_LOG_ONCE();
448+
return false;
461449
}
462450

463451
base::TimeDelta WaylandScreen::CalculateIdleTime() const {

chromium/ui/ozone/platform/wayland/host/wayland_screen.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ class WaylandConnection;
3838
class OrgGnomeMutterIdleMonitor;
3939
#endif
4040

41-
// A PlatformScreen implementation for Wayland.
41+
// A PlatformScreen implementation for Wayland. Note that this object outlives
42+
// WaylandConnection.
4243
class WaylandScreen : public PlatformScreen, public DeviceScaleFactorObserver {
4344
public:
4445
explicit WaylandScreen(WaylandConnection* connection);
@@ -134,7 +135,6 @@ class WaylandScreen : public PlatformScreen, public DeviceScaleFactorObserver {
134135
org_gnome_mutter_idle_monitor_;
135136
#endif
136137

137-
wl::Object<zwp_idle_inhibitor_v1> idle_inhibitor_;
138138
uint32_t screen_saver_suspension_count_ = 0;
139139

140140
base::ScopedObservation<ui::LinuxUi, DeviceScaleFactorObserver>

chromium/ui/ozone/platform/wayland/host/zwp_idle_inhibit_manager.cc

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88

99
#include "base/logging.h"
1010
#include "ui/ozone/platform/wayland/host/wayland_connection.h"
11+
#include "ui/ozone/platform/wayland/host/wayland_surface.h"
12+
#include "ui/ozone/platform/wayland/host/wayland_window.h"
1113

1214
namespace ui {
1315

@@ -45,14 +47,37 @@ void ZwpIdleInhibitManager::Instantiate(WaylandConnection* connection,
4547
ZwpIdleInhibitManager::ZwpIdleInhibitManager(
4648
zwp_idle_inhibit_manager_v1* manager,
4749
WaylandConnection* connection)
48-
: manager_(manager) {}
50+
: connection_(connection), manager_(manager) {}
4951

5052
ZwpIdleInhibitManager::~ZwpIdleInhibitManager() = default;
5153

52-
wl::Object<zwp_idle_inhibitor_v1> ZwpIdleInhibitManager::CreateInhibitor(
53-
wl_surface* surface) {
54-
return wl::Object<zwp_idle_inhibitor_v1>(
55-
zwp_idle_inhibit_manager_v1_create_inhibitor(manager_.get(), surface));
54+
bool ZwpIdleInhibitManager::CreateInhibitor() {
55+
// Wayland inhibits idle behaviour on certain output, and implies that a
56+
// surface bound to that output should obtain the inhibitor and hold it
57+
// until it no longer needs to prevent the output to go idle.
58+
// We assume that the idle lock is initiated by the user, and therefore the
59+
// surface that we should use is the one owned by the window that is focused
60+
// currently.
61+
const auto* window_manager = connection_->window_manager();
62+
DCHECK(window_manager);
63+
auto* current_window = window_manager->GetCurrentFocusedWindow();
64+
if (!current_window) {
65+
LOG(WARNING) << "Cannot inhibit going idle when no window is focused";
66+
return false;
67+
}
68+
69+
DCHECK(current_window->root_surface());
70+
auto new_inhibitor = wl::Object<zwp_idle_inhibitor_v1>(
71+
zwp_idle_inhibit_manager_v1_create_inhibitor(
72+
manager_.get(), current_window->root_surface()->surface()));
73+
74+
idle_inhibitor_.swap(new_inhibitor);
75+
return true;
76+
}
77+
78+
void ZwpIdleInhibitManager::RemoveInhibitor() {
79+
inhibiting_window_ = nullptr;
80+
idle_inhibitor_.reset();
5681
}
5782

5883
} // namespace ui

chromium/ui/ozone/platform/wayland/host/zwp_idle_inhibit_manager.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,13 @@
55
#ifndef UI_OZONE_PLATFORM_WAYLAND_HOST_ZWP_IDLE_INHIBIT_MANAGER_H_
66
#define UI_OZONE_PLATFORM_WAYLAND_HOST_ZWP_IDLE_INHIBIT_MANAGER_H_
77

8+
#include "base/memory/weak_ptr.h"
89
#include "ui/ozone/platform/wayland/common/wayland_object.h"
910

1011
namespace ui {
1112

1213
class WaylandConnection;
14+
class WaylandWindow;
1315

1416
// Wraps the idle inhibit manager, which is provided via
1517
// zwp_idle_inhibit_manager_v1 interface.
@@ -30,11 +32,19 @@ class ZwpIdleInhibitManager
3032
ZwpIdleInhibitManager& operator=(const ZwpIdleInhibitManager&) = delete;
3133
~ZwpIdleInhibitManager();
3234

33-
wl::Object<zwp_idle_inhibitor_v1> CreateInhibitor(wl_surface* surface);
35+
bool CreateInhibitor();
36+
void RemoveInhibitor();
37+
38+
bool is_inhibiting() const { return !!inhibiting_window_; }
3439

3540
private:
41+
const raw_ptr<WaylandConnection> connection_;
42+
3643
// Wayland object wrapped by this class.
3744
wl::Object<zwp_idle_inhibit_manager_v1> manager_;
45+
46+
base::WeakPtr<WaylandWindow> inhibiting_window_;
47+
wl::Object<zwp_idle_inhibitor_v1> idle_inhibitor_;
3848
};
3949

4050
} // namespace ui

0 commit comments

Comments
 (0)