diff --git a/nix/patches/qtbase-wayland-screen-uaf.patch b/nix/patches/qtbase-wayland-screen-uaf.patch index 1b1a326..1c4808b 100644 --- a/nix/patches/qtbase-wayland-screen-uaf.patch +++ b/nix/patches/qtbase-wayland-screen-uaf.patch @@ -1,5 +1,5 @@ diff --git a/src/plugins/platforms/wayland/qwaylanddisplay.cpp b/src/plugins/platforms/wayland/qwaylanddisplay.cpp -index 02169e77..a1f3befe 100644 +index 02169e77..43ab00fa 100644 --- a/src/plugins/platforms/wayland/qwaylanddisplay.cpp +++ b/src/plugins/platforms/wayland/qwaylanddisplay.cpp @@ -423,8 +423,10 @@ void QWaylandDisplay::reconnect() @@ -15,7 +15,7 @@ index 02169e77..a1f3befe 100644 while (!mScreens.isEmpty()) { auto screen = mScreens.takeLast(); -@@ -603,6 +605,22 @@ QWaylandScreen *QWaylandDisplay::screenForOutput(struct wl_output *output) const +@@ -603,6 +605,27 @@ QWaylandScreen *QWaylandDisplay::screenForOutput(struct wl_output *output) const return nullptr; } @@ -29,6 +29,11 @@ index 02169e77..a1f3befe 100644 + mSurfaces.removeOne(surface); +} + ++bool QWaylandDisplay::isScreenAlive(QWaylandScreen *screen) const ++{ ++ return mScreens.contains(screen) || mWaitingScreens.contains(screen); ++} ++ +void QWaylandDisplay::forgetScreenForSurfaces(QWaylandScreen *screen) +{ + for (auto *surface : std::as_const(mSurfaces)) @@ -38,7 +43,7 @@ index 02169e77..a1f3befe 100644 void QWaylandDisplay::handleScreenInitialized(QWaylandScreen *screen) { if (!mWaitingScreens.removeOne(screen)) -@@ -823,6 +841,7 @@ void QWaylandDisplay::registry_global_remove(uint32_t id) +@@ -823,6 +846,7 @@ void QWaylandDisplay::registry_global_remove(uint32_t id) for (auto *screen : mWaitingScreens) { if (screen->outputId() == id) { mWaitingScreens.removeOne(screen); @@ -46,7 +51,7 @@ index 02169e77..a1f3befe 100644 delete screen; break; } -@@ -831,6 +850,7 @@ void QWaylandDisplay::registry_global_remove(uint32_t id) +@@ -831,6 +855,7 @@ void QWaylandDisplay::registry_global_remove(uint32_t id) for (QWaylandScreen *screen : std::as_const(mScreens)) { if (screen->outputId() == id) { mScreens.removeOne(screen); @@ -55,20 +60,21 @@ index 02169e77..a1f3befe 100644 ensureScreen(); QWindowSystemInterface::handleScreenRemoved(screen); diff --git a/src/plugins/platforms/wayland/qwaylanddisplay_p.h b/src/plugins/platforms/wayland/qwaylanddisplay_p.h -index 29952886..0baa378f 100644 +index 29952886..88b57945 100644 --- a/src/plugins/platforms/wayland/qwaylanddisplay_p.h +++ b/src/plugins/platforms/wayland/qwaylanddisplay_p.h -@@ -116,6 +116,9 @@ public: +@@ -116,6 +116,10 @@ public: QPlatformPlaceholderScreen *placeholderScreen() const { return mPlaceholderScreen; } void ensureScreen(); + void registerSurface(QWaylandSurface *surface); + void unregisterSurface(QWaylandSurface *surface); ++ bool isScreenAlive(QWaylandScreen *screen) const; + QWaylandScreen *screenForOutput(struct wl_output *output) const; void handleScreenInitialized(QWaylandScreen *screen); -@@ -289,6 +292,7 @@ private: +@@ -289,6 +293,7 @@ private: void checkWaylandError(); void reconnect(); void setupConnection(); @@ -76,7 +82,7 @@ index 29952886..0baa378f 100644 void handleWaylandSync(); void requestWaylandSync(); -@@ -311,6 +315,7 @@ private: +@@ -311,6 +316,7 @@ private: QList mScreens; QPlatformPlaceholderScreen *mPlaceholderScreen = nullptr; QList mInputDevices; @@ -85,10 +91,10 @@ index 29952886..0baa378f 100644 QWaylandIntegration *mWaylandIntegration = nullptr; #if QT_CONFIG(cursor) diff --git a/src/plugins/platforms/wayland/qwaylandsurface.cpp b/src/plugins/platforms/wayland/qwaylandsurface.cpp -index 274fdda8..b37e9265 100644 +index 274fdda8..fd098066 100644 --- a/src/plugins/platforms/wayland/qwaylandsurface.cpp +++ b/src/plugins/platforms/wayland/qwaylandsurface.cpp -@@ -13,13 +13,16 @@ namespace QtWaylandClient { +@@ -13,18 +13,31 @@ namespace QtWaylandClient { QWaylandSurface::QWaylandSurface(QWaylandDisplay *display) : wl_surface(display->createSurface(this)) @@ -105,6 +111,21 @@ index 274fdda8..b37e9265 100644 destroy(); } + QWaylandScreen *QWaylandSurface::oldestEnteredScreen() + { ++ // Prune any screen pointers that the display no longer knows about. ++ // This guards against every possible stale-pointer path: waiting-screen ++ // deletion, signal-ordering gaps during ensureScreen(), and any future ++ // code that removes a screen without notifying surfaces. ++ if (m_display) { ++ m_screens.removeIf([this](QWaylandScreen *s) { ++ return !m_display->isScreenAlive(s); ++ }); ++ } ++ + for (auto *screen : std::as_const(m_screens)) { + // only report valid screens + // we can have some ouptuts waiting for xdg output information diff --git a/src/plugins/platforms/wayland/qwaylandsurface_p.h b/src/plugins/platforms/wayland/qwaylandsurface_p.h index 41860297..ddb63b04 100644 --- a/src/plugins/platforms/wayland/qwaylandsurface_p.h