e_policy: Fix use-after-free 15/318115/1
authorSeunghun Lee <shiin@samsung.com>
Tue, 24 Sep 2024 07:11:12 +0000 (16:11 +0900)
committerTizen Window System <tizen.windowsystem@gmail.com>
Tue, 24 Sep 2024 23:43:05 +0000 (08:43 +0900)
Removing a listener from the buffer_clear signal of E_Pixmap after
E_Pixmap has been destroyed results in use-after-free issue.

To resolve this problem, E_Pixmap will emit the destroy signal just
before it's destroyed. The implementation using E_Pixmap should remove
all listeners from the E_Pixmap when destroy signal is emitted.

Change-Id: I38f9fd86fd4815f156cc74bfc7934c79a55fbc6f

src/bin/core/e_pixmap.c
src/bin/core/e_pixmap_intern.h
src/bin/windowmgr/e_policy.c
src/bin/windowmgr/e_policy_intern.h

index d8e88f6..cbb09c7 100644 (file)
@@ -52,6 +52,7 @@ struct _E_Pixmap
    struct wl_listener surface_resource_destroy;
 
    struct {
+      struct wl_signal destroy;
       struct wl_signal buffer_clear;
       struct wl_signal buffer_clear_done;
    } events;
@@ -180,6 +181,7 @@ _e_pixmap_new(E_Pixmap_Type type)
    cp->cdata->pending.buffer_viewport.changed = 0;
    cp->own_cdata = EINA_TRUE;
 
+   wl_signal_init(&cp->events.destroy);
    wl_signal_init(&cp->events.buffer_clear);
    wl_signal_init(&cp->events.buffer_clear_done);
 
@@ -206,6 +208,7 @@ e_pixmap_free(E_Pixmap *cp)
    if (cp->usable)
      e_pixmap_usable_set(cp, 0);
 
+   wl_signal_emit(&cp->events.destroy, cp);
    _e_pixmap_hook_call(E_PIXMAP_HOOK_DEL, cp);
    e_pixmap_image_clear(cp, EINA_FALSE);
    eina_hash_del_by_key(res_ids, &cp->res_id);
@@ -959,6 +962,12 @@ e_pixmap_buffer_type_get(E_Pixmap *pixmap)
 }
 
 EINTERN void
+e_pixmap_destroy_listener_add(E_Pixmap *pixmap, struct wl_listener *listener)
+{
+   wl_signal_add(&pixmap->events.destroy, listener);
+}
+
+EINTERN void
 e_pixmap_buffer_clear_listener_add(E_Pixmap *pixmap, struct wl_listener *listener)
 {
    EINA_SAFETY_ON_NULL_RETURN(pixmap);
index 6786cbd..b68bd2f 100644 (file)
@@ -32,6 +32,7 @@ EINTERN void         *e_pixmap_ref_resource_get(E_Pixmap *cp);
 EINTERN E_Comp_Wl_Buffer_Type e_pixmap_buffer_type_get(E_Pixmap *pixmap);
 EINTERN void                  e_pixmap_buffer_clear_done_send(E_Pixmap *pixmap);
 
+EINTERN void          e_pixmap_destroy_listener_add(E_Pixmap *pixmap, struct wl_listener *listener);
 EINTERN void          e_pixmap_buffer_clear_listener_add(E_Pixmap *pixmap, struct wl_listener *listener);
 EINTERN void          e_pixmap_buffer_clear_done_listener_add(E_Pixmap *pixmap, struct wl_listener *listener);
 
index 99a55a6..0ee5105 100644 (file)
@@ -219,6 +219,7 @@ static void
 _e_policy_client_del(E_Policy_Client *pc)
 {
    wl_list_remove(&pc->pixmap_buffer_clear.link);
+   wl_list_remove(&pc->pixmap_destroy.link);
 
    if (pc->buffer_flush_timer)
      ecore_timer_del(pc->buffer_flush_timer);
@@ -2456,6 +2457,20 @@ _e_policy_client_cb_pixmap_buffer_clear(struct wl_listener *listener, void *data
      _e_policy_client_pixmap_buffer_clear(policy_client, only_free);
 }
 
+static void
+_e_policy_client_cb_pixmap_destroy(struct wl_listener *listener, void *data)
+{
+   E_Policy_Client *pc;
+
+   pc = wl_container_of(listener, pc, pixmap_destroy);
+
+   wl_list_remove(&pc->pixmap_buffer_clear.link);
+   wl_list_init(&pc->pixmap_buffer_clear.link);
+
+   wl_list_remove(&pc->pixmap_destroy.link);
+   wl_list_init(&pc->pixmap_destroy.link);
+}
+
 EINTERN E_Policy_Client *
 e_policy_client_add(E_Client *ec)
 {
@@ -2478,6 +2493,9 @@ e_policy_client_add(E_Client *ec)
    _e_policy_desk_client_add_hook_add(pc);
 
    // pixmap listener add
+   pc->pixmap_destroy.notify = _e_policy_client_cb_pixmap_destroy;
+   e_pixmap_destroy_listener_add(ec->pixmap, &pc->pixmap_destroy);
+
    pc->pixmap_buffer_clear.notify = _e_policy_client_cb_pixmap_buffer_clear;
    e_pixmap_buffer_clear_listener_add(ec->pixmap, &pc->pixmap_buffer_clear);
 
index 95cca29..74a5119 100644 (file)
@@ -72,6 +72,7 @@ struct _E_Policy_Client
    Ecore_Timer *buffer_flush_timer;
    Eina_Bool buffer_flush_only_free;
 
+   struct wl_listener pixmap_destroy;
    struct wl_listener pixmap_buffer_clear;
 };