fix: capturev1 resource destroy callbacks: use deleteLater() to avoid UAF#811
Open
felixonmars wants to merge 1 commit intolinuxdeepin:masterfrom
Open
fix: capturev1 resource destroy callbacks: use deleteLater() to avoid UAF#811felixonmars wants to merge 1 commit intolinuxdeepin:masterfrom
felixonmars wants to merge 1 commit intolinuxdeepin:masterfrom
Conversation
… UAF
When WClient::destroyed fires (from ~QObject of a WClient being deleted),
the connected slots in treeland_capture_{context,session,frame}_v1::setResource
call wl_resource_destroy(this->resource). This triggers the wl_resource destructor
callback (capture_{context,session,frame}_resource_destroy) which immediately calls
'delete this' — deleting the Qt receiver QObject while Qt's doActivate() is still
iterating its WClient::destroyed connection list.
The immediate deletion calls ~QObject() → removeConnection() → c->deref(), which
can free the Connection object c that doActivate() currently holds as a raw pointer.
On the next loop iteration, c->nextConnectionList.loadRelaxed() reads freed memory,
resulting in a UAF crash at QBasicAtomicPointer::loadRelaxed (qobject.cpp:4317):
doActivate → list->first.loadRelaxed() → c->receiver OK
→ c->receiverThreadData → td (non-null but freed) → td->threadId SIGSEGV
Fix: replace 'delete session/context/frame' with deleteLater() and null out the
resource pointer first. This defers the QObject destruction to the next event loop
iteration, after doActivate() has finished iterating connections. Also add null guards
in the WClient::destroyed slots since resource is now set to nullptr by the callbacks.
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: felixonmars The full list of commands accepted by this bot can be found here. DetailsNeeds approval from an approver in each of these files:Approvers can indicate their approval by writing |
Reviewer's guide (collapsed on small PRs)Reviewer's GuideThis PR fixes a use-after-free caused by immediate deletion of capturev1 QObject wrappers from Wayland wl_resource destroy callbacks by deferring their destruction with deleteLater(), nulling their wl_resource pointers, and guarding WClient::destroyed handlers against double/destroy-after-free by checking the resource pointer before calling wl_resource_destroy(). Sequence diagram for fixed WClient destruction and capturev1 resource teardownsequenceDiagram
actor Client
participant WClient
participant QtSignal as QObject_doActivate
participant CaptureObj as treeland_capture_session_v1
participant WLRes as wl_resource
Client ->> WClient: destroy WClient instance
activate WClient
WClient ->> QtSignal: emit destroyed
activate QtSignal
QtSignal ->> CaptureObj: invoke WClient_destroyed_lambda
activate CaptureObj
alt resource is non null
CaptureObj ->> WLRes: wl_resource_destroy(resource)
activate WLRes
WLRes ->> CaptureObj: capture_session_resource_destroy(resource)
Note over CaptureObj: Q_EMIT beforeDestroy()
CaptureObj ->> CaptureObj: resource = nullptr
CaptureObj ->> CaptureObj: deleteLater()
deactivate WLRes
else resource is null
CaptureObj ->> CaptureObj: skip wl_resource_destroy
end
deactivate CaptureObj
QtSignal ->> QtSignal: finish iterating connections
deactivate QtSignal
deactivate WClient
participant QtEventLoop
QtEventLoop ->> CaptureObj: process pending deleteLater
CaptureObj ->> CaptureObj: QObject destructor runs
Class diagram for updated capturev1 objects and resource handlingclassDiagram
class WClient {
}
class wl_resource {
}
class treeland_capture_context_v1 {
wl_resource* resource
+void setResource(wl_client* client, wl_resource* resource)
}
class treeland_capture_session_v1 {
wl_resource* resource
+void setResource(wl_client* client, wl_resource* resource)
}
class treeland_capture_frame_v1 {
wl_resource* resource
+void setResource(wl_client* client, wl_resource* resource)
}
class QtQObject {
+void deleteLater()
+signal destroyed()
}
QtQObject <|-- WClient
QtQObject <|-- treeland_capture_context_v1
QtQObject <|-- treeland_capture_session_v1
QtQObject <|-- treeland_capture_frame_v1
WClient --> treeland_capture_context_v1 : destroyed connection
WClient --> treeland_capture_session_v1 : destroyed connection
WClient --> treeland_capture_frame_v1 : destroyed connection
treeland_capture_context_v1 --> wl_resource : resource
treeland_capture_session_v1 --> wl_resource : resource
treeland_capture_frame_v1 --> wl_resource : resource
class capture_context_resource_destroy {
+void capture_context_resource_destroy(wl_resource* resource)
}
class capture_session_resource_destroy {
+void capture_session_resource_destroy(wl_resource* resource)
}
class capture_frame_resource_destroy {
+void capture_frame_resource_destroy(wl_resource* resource)
}
capture_context_resource_destroy --> treeland_capture_context_v1 : null resource then deleteLater
capture_session_resource_destroy --> treeland_capture_session_v1 : null resource then deleteLater
capture_frame_resource_destroy --> treeland_capture_frame_v1 : null resource then deleteLater
class wl_client {
}
class WClient_static {
+WClient* get(wl_client* client)
}
WClient_static ..> WClient : get
treeland_capture_context_v1 ..> WClient_static : setResource
treeland_capture_session_v1 ..> WClient_static : setResource
treeland_capture_frame_v1 ..> WClient_static : setResource
File-Level Changes
Possibly linked issues
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
zccrs
requested changes
Mar 31, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
When WClient::destroyed fires (from ~QObject of a WClient being deleted), the connected slots in
treeland_capture_{context,session,frame}_v1::setResourcecall wl_resource_destroy(this->resource). This triggers the wl_resource destructor callback (capture_{context,session,frame}_resource_destroy) which immediately calls 'delete this' — deleting the Qt receiver QObject while Qt's doActivate() is still iterating its WClient::destroyed connection list.The immediate deletion calls ~QObject() → removeConnection() → c->deref(), which can free the Connection object c that doActivate() currently holds as a raw pointer. On the next loop iteration, c->nextConnectionList.loadRelaxed() reads freed memory, resulting in a UAF crash at QBasicAtomicPointer::loadRelaxed (qobject.cpp:4317):
Fix: replace 'delete session/context/frame' with deleteLater() and null out the resource pointer first. This defers the QObject destruction to the next event loop iteration, after doActivate() has finished iterating connections. Also add null guards in the WClient::destroyed slots since resource is now set to nullptr by the callbacks.
Summary by Sourcery
Defer destruction of capture v1 context/session/frame objects on Wayland resource teardown to avoid use-after-free when WClient is destroyed.
Bug Fixes:
Enhancements: