tu/kgsl: Fix KGSL syncobj lifetime in no CB submit

The temporary syncobj created in the fast path of kgsl_queue_submit was
not being destroyed, and potentially being assigned to multiple syncobjs
without being properly duplicated. This could lead to a use-after-free
or double-free since multiple syncobjs could be assigned the same FD.

Signed-off-by: Mark Collins <mark@igalia.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/34328>
This commit is contained in:
Mark Collins
2025-03-31 19:56:37 +00:00
committed by Marge Bot
parent cf4bd2e412
commit e4359cc49c
+31 -5
View File
@@ -463,12 +463,11 @@ kgsl_syncobj_reset(struct kgsl_syncobj *s)
if (s->state == KGSL_SYNCOBJ_STATE_FD && s->fd >= 0) {
ASSERTED int ret = close(s->fd);
assert(ret == 0);
s->fd = -1;
} else if (s->state == KGSL_SYNCOBJ_STATE_TS) {
s->timestamp = UINT32_MAX;
}
s->state = KGSL_SYNCOBJ_STATE_UNSIGNALED;
s->timestamp = UINT32_MAX;
s->fd = -1;
}
static void
@@ -477,6 +476,17 @@ kgsl_syncobj_destroy(struct kgsl_syncobj *s)
kgsl_syncobj_reset(s);
}
static struct kgsl_syncobj
kgsl_syncobj_dup(struct kgsl_syncobj *s)
{
struct kgsl_syncobj dups = *s;
if (s->state == KGSL_SYNCOBJ_STATE_FD && s->fd >= 0) {
dups.fd = dup(s->fd);
assert(dups.fd >= 0);
}
return dups;
}
static int
timestamp_to_fd(struct tu_queue *queue, uint32_t timestamp)
{
@@ -1122,15 +1132,31 @@ kgsl_queue_submit(struct tu_queue *queue, void *_submit,
assert(wait_sync.state !=
KGSL_SYNCOBJ_STATE_UNSIGNALED); // Would wait forever
for (uint32_t i = 0; i < signal_count; i++) {
if (signal_count == 1) {
/* Move instead of duplicating the syncobj, as we don't need to
* keep the original one around.
*/
struct kgsl_syncobj *signal_sync =
&container_of(signals[i].sync, struct vk_kgsl_syncobj, vk)
&container_of(signals[0].sync, struct vk_kgsl_syncobj, vk)
->syncobj;
kgsl_syncobj_reset(signal_sync);
*signal_sync = wait_sync;
} else {
for (uint32_t i = 0; i < signal_count; i++) {
struct kgsl_syncobj *signal_sync =
&container_of(signals[i].sync, struct vk_kgsl_syncobj, vk)
->syncobj;
kgsl_syncobj_reset(signal_sync);
*signal_sync = kgsl_syncobj_dup(&wait_sync);
}
kgsl_syncobj_destroy(&wait_sync);
}
kgsl_syncobj_destroy(&last_submit_sync);
return VK_SUCCESS;
}