Fix list traversal issue in client_calc_layer
authorpldubouilh <pldubouilh@gmail.com>
Fri, 17 Mar 2023 17:23:47 +0000 (18:23 +0100)
committerMikael Magnusson <mikachu@gmail.com>
Mon, 20 Mar 2023 06:28:02 +0000 (07:28 +0100)
The calls to client_calc_layer_internal can modify stacking_list, which
can cause us to follow dangling ->next pointers (either by the pointer
itself already being freed, or it pointing to a freed area). Avoid this
by copying the list first, the goal is to visit every client in the list
once so this should be fine.

openbox/client.c

index 7168b24078b7d9da330857489301cd8f44522670..b8264587c168c50763181011e106a4a81ea73144 100644 (file)
@@ -2742,9 +2742,12 @@ static void client_calc_layer_internal(ObClient *self)
 void client_calc_layer(ObClient *self)
 {
     GList *it;
+    /* the client_calc_layer_internal calls below modify stacking_list,
+       so we have to make a copy to iterate over */
+    GList *list = g_list_copy(stacking_list);
 
     /* skip over stuff above fullscreen layer */
-    for (it = stacking_list; it; it = g_list_next(it))
+    for (it = list; it; it = g_list_next(it))
         if (window_layer(it->data) <= OB_STACKING_LAYER_FULLSCREEN) break;
 
     /* find the windows in the fullscreen layer, and mark them not-visited */
@@ -2757,7 +2760,7 @@ void client_calc_layer(ObClient *self)
     client_calc_layer_internal(self);
 
     /* skip over stuff above fullscreen layer */
-    for (it = stacking_list; it; it = g_list_next(it))
+    for (it = list; it; it = g_list_next(it))
         if (window_layer(it->data) <= OB_STACKING_LAYER_FULLSCREEN) break;
 
     /* now recalc any windows in the fullscreen layer which have not
@@ -2768,6 +2771,8 @@ void client_calc_layer(ObClient *self)
                  !WINDOW_AS_CLIENT(it->data)->visited)
             client_calc_layer_internal(it->data);
     }
+
+    g_list_free(it);
 }
 
 gboolean client_should_show(ObClient *self)