mirror of
https://github.com/yshui/picom.git
synced 2025-04-14 17:53:25 -04:00
wm/tree: fix potential use-after-free in tree changes
If a toplevel is reparented, then destroy, any WM_TREE_CHANGE_CLIENT events currently queued will reference the freed toplevel node. Note this doesn't happen when the toplevel is destroyed directly. Because in that case it will be turned into a zombie, and is guaranteed to only be freed after the client change event is handled. With this commit, when a toplevel is killed (i.e. destroyed or reparented), all currently queued tree changes will be updated to reference the zombie instead. Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
This commit is contained in:
parent
7d216657d0
commit
bb5d026a6f
1 changed files with 14 additions and 5 deletions
|
@ -40,16 +40,25 @@ static void wm_tree_enqueue_change(struct wm_tree *tree, struct wm_tree_change c
|
|||
// `WM_TREE_CHANGE_TOPLEVEL_NEW` change in the queue.
|
||||
bool found = false;
|
||||
list_foreach_safe(struct wm_tree_change_list, i, &tree->changes, siblings) {
|
||||
if (i->item.type == WM_TREE_CHANGE_TOPLEVEL_NEW &&
|
||||
wm_treeid_eq(i->item.toplevel, change.toplevel)) {
|
||||
if (!wm_treeid_eq(i->item.toplevel, change.toplevel)) {
|
||||
continue;
|
||||
}
|
||||
if (i->item.type == WM_TREE_CHANGE_TOPLEVEL_NEW) {
|
||||
list_remove(&i->siblings);
|
||||
list_insert_after(&tree->free_changes, &i->siblings);
|
||||
found = true;
|
||||
} else if (wm_treeid_eq(i->item.toplevel, change.toplevel) && found) {
|
||||
// We also need to delete all other changes related to
|
||||
// this toplevel in between the new and gone changes.
|
||||
} else if (found) {
|
||||
// We also need to delete all other changes
|
||||
// related to this toplevel in between the new and
|
||||
// gone changes.
|
||||
list_remove(&i->siblings);
|
||||
list_insert_after(&tree->free_changes, &i->siblings);
|
||||
} else if (i->item.type == WM_TREE_CHANGE_CLIENT) {
|
||||
// Need to update client changes, so they points to the
|
||||
// zombie instead of the old toplevel node, since the old
|
||||
// toplevel node could be freed before tree changes are
|
||||
// processed.
|
||||
i->item.client.toplevel = change.killed;
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
|
|
Loading…
Add table
Reference in a new issue