e_hwc_window_queue: Fix use after free of the queue buffer 68/325068/1
authorChangyeon Lee <cyeon.lee@samsung.com>
Tue, 27 May 2025 09:33:01 +0000 (18:33 +0900)
committerTizen Window System <tizen.windowsystem@gmail.com>
Mon, 2 Jun 2025 07:38:11 +0000 (16:38 +0900)
the queue buffer can be used after it is freed in the detach
callback when tbm_surface_queue is destroyed and exported buffer
is not destroyed.

for fixing problem of the use after free, this patch unset
detach callback of exported buffer when the queue buffer is
destroyed.

Change-Id: If10cbb9e9a072ca9c4aaea7f02b096cde47a7e21

src/bin/displaymgr/e_hwc_window_queue.c

index 94532866d8ca7b7d2997f2cacf3233536c201da2..cccebd3ca6eee578cb56f9bf82d74772be430383 100644 (file)
@@ -445,7 +445,10 @@ _e_hwc_window_queue_buffer_destroy(E_Hwc_Window_Queue_Buffer *queue_buffer)
    EINA_SAFETY_ON_FALSE_RETURN(queue_buffer);
 
    if (queue_buffer->exported_wl_buffer)
-     wl_list_remove(&queue_buffer->exported_destroy_listener.link);
+     {
+        wayland_tbm_server_export_buffer_set_detach_cb(queue_buffer->exported_wl_buffer, NULL, NULL);
+        wl_list_remove(&queue_buffer->exported_destroy_listener.link);
+     }
 
    EHWQTRACE("DESTROY queue buffer:%p tq:%p tsurface:%p",
              NULL, (queue_buffer->queue ? queue_buffer->queue->hwc : NULL),
@@ -581,11 +584,10 @@ _e_hwc_window_queue_buffer_export(E_Hwc_Window_Queue *queue, E_Hwc_Window_Queue_
    if (queue_buffer->exported) return EINA_TRUE;
 
    /* export the tbm_surface(wl_buffer) to the client_queue */
-   wl_buffer = wayland_tbm_server_client_queue_export_buffer2(user->cqueue, queue_buffer->tsurface,
-                                                              E_HWC_WINDOW_QUEUE_BUFFER_FLAGS,
-                                                              _e_hwc_window_queue_exported_buffer_detach_cb,
-                                                              NULL,
-                                                              (void *)queue);
+   wl_buffer = wayland_tbm_server_client_queue_export_buffer(user->cqueue, queue_buffer->tsurface,
+                                                             E_HWC_WINDOW_QUEUE_BUFFER_FLAGS,
+                                                             _e_hwc_window_queue_exported_buffer_detach_cb,
+                                                             (void *)queue);
    EINA_SAFETY_ON_FALSE_RETURN_VAL(wl_buffer, EINA_FALSE);
 
    EHWQINF("EXP ts:%p tq:%p wl_buffer:%p",
@@ -803,6 +805,20 @@ _e_hwc_window_queue_cb_dequeueable(tbm_surface_queue_h surface_queue, void *data
      }
 }
 
+static void
+_e_hwc_window_queue_user_unset(E_Hwc_Window_Queue *queue)
+{
+   if (!queue->user) return;
+
+   EHWQINF("Unset user ehw:%p - {%s}",
+            queue->user->ec, queue->hwc, queue, queue->user,
+            (queue->user->ec ? queue->user->ec->icccm.title : "UNKNOWN"));
+
+   e_hwc_window_restriction_unset(queue->user, E_HWC_WINDOW_RESTRICTION_QUEUE_UNSET_WAITING);
+   e_hwc_window_unref(queue->user);
+   queue->user = NULL;
+}
+
 static void
 _e_hwc_window_queue_free(E_Hwc_Window_Queue *queue)
 {
@@ -832,6 +848,10 @@ _e_hwc_window_queue_destroy(E_Hwc_Window_Queue *queue)
 
    queue->tqueue = NULL;
 
+   _e_hwc_window_queue_user_unset(queue);
+
+   queue->state = E_HWC_WINDOW_QUEUE_STATE_UNSET;
+
    e_object_del(E_OBJECT(queue));
 }
 
@@ -1670,20 +1690,12 @@ _e_hwc_window_queue_unset(E_Hwc_Window_Queue *queue)
 
    /* release the tqueue */
    _e_hwc_window_queue_tqueue_release(queue->tqueue, queue->user);
-
-   EHWQINF("Unset user ehw:%p - {%s}",
-           queue->user->ec, queue->hwc, queue, queue->user,
-           (queue->user->ec ? queue->user->ec->icccm.title : "UNKNOWN"));
-
-   /* unset the hwc_window from the queue */
-   e_hwc_window_restriction_unset(queue->user, E_HWC_WINDOW_RESTRICTION_QUEUE_UNSET_WAITING);
-   e_hwc_window_unref(queue->user);
-   queue->user = NULL;
+   _e_hwc_window_queue_user_unset(queue);
 
    /* set the queue_state_unset */
    queue->state = E_HWC_WINDOW_QUEUE_STATE_UNSET;
 
-   if (eina_list_count(queue->user_pending_set))
+   if (queue->tqueue && eina_list_count(queue->user_pending_set))
      _e_hwc_window_queue_unset_event_add(queue);
 
    e_object_unref(E_OBJECT(queue));