Skip to content

window-zoom: fix use-after-free in fini() when the zoomed view is gone - #352

Open
bornmw wants to merge 1 commit into
WayfireWM:masterfrom
bornmw:winzoom-fix-uaf-fini
Open

bornmw wants to merge 1 commit into
WayfireWM:masterfrom
bornmw:winzoom-fix-uaf-fini

Conversation

@bornmw

@bornmw bornmw commented Oct 10, 2026 •

Copy link
Copy Markdown

Fixes #351.

The transformers map keyed on a raw view pointer was only cleaned up in fini(), which dereferenced every key. A zoomed window closed before the plugin was disabled left a dangling pointer; the later fini() dereferenced it (heap-use-after-free, deterministic under AddressSanitizer). The scale->1.0 path also removed the transformer from the node tree while retaining the map entry.

Follows the pattern used by the keycolor plugin: transformer_name member, pop_transformer() with a get_transformer() guard, and remove_transformers() iterating wf::get_core().get_all_views() (live views only) from fini(), after which the map is cleared. fini() no longer dereferences a map key.

Verified with the ASan repro from the issue (nested wayfire on top of a live session, zoom triggered through the plugin's own update_winzoom()): stock build crashes with the reported use-after-free; this build unloads cleanly with no report.

@soreau soreau left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea seems like a good way to fix the problem. Just a few things that need to be addressed. See other comments.

Comment thread src/window-zoom.cpp Outdated
}
// Only touch live views: the map may hold entries for views that
// were destroyed while zoomed, and dereferencing them here is a
// use-after-free.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment is gratuitous. We could do without it. It does show that we could do better though, like handling view unmap signal and removing from the transformers list. However going even further, there is probably a way to omit transformers map altogether. This was written a long time ago and the plugin API has changed over time so some of this stuff might be for hysterical reasons.

Comment thread src/window-zoom.cpp Outdated
// were destroyed while zoomed, and dereferencing them here is a
// use-after-free.
remove_transformers();
transformers.clear();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The .clear() line could be moved to remove_transformers() function.

Comment thread src/window-zoom.cpp Outdated
private:
void pop_transformer(wayfire_view view)
{
auto it = transformers.find(view);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do not need to .find() the view here. I would like to see keycolor pop_transformer() function copied.

Comment thread src/window-zoom.cpp Outdated
return;
}

if (it->first->get_transformed_node()->get_transformer(transformer_name))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it->first can be replaced with view.

Comment thread src/window-zoom.cpp Outdated
it->first->get_transformed_node()->rem_transformer(it->second);
}

transformers.erase(it);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is unnecessary.

@bornmw
bornmw force-pushed the winzoom-fix-uaf-fini branch from 5748ec4 to 779aba3 Compare October 10, 2026 20:00
@bornmw

bornmw commented Oct 10, 2026

Copy link
Copy Markdown
Author

Addressed in 779aba3:

  • pop_transformer() is now the keycolor function verbatim (no .find(), view used directly, no map erase)
  • .clear() moved into remove_transformers()
  • comment in fini() dropped

Re-verified with the ASan repro from the issue (nested wayfire, zoom triggered through update_winzoom()): zoomed window closed, plugin unloaded — no reports, clean fini.

@bornmw
bornmw requested a review from soreau October 10, 2026 20:03

@soreau soreau left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks much better, thanks!

@bornmw
bornmw force-pushed the winzoom-fix-uaf-fini branch from 779aba3 to 0ad3736 Compare October 11, 2026 01:35
The transformers map keyed on a raw view pointer was only cleaned up in
fini(), which dereferenced every key. A zoomed window closed before the
plugin was disabled left a dangling pointer, and the later fini()
dereferenced it (heap-use-after-free -> segfault, whole session lost;
deterministic under AddressSanitizer). The scale->1.0 path also removed
the transformer from the node tree while retaining the map entry.

Follow the pattern used by keycolor: a transformer_name member,
pop_transformer() with a get_transformer() guard, and
remove_transformers() which iterates wf::get_core().get_all_views()
(live views only) in fini(). The map is then cleared, so fini() never
dereferences a map key and no entry outlives the plugin.
@bornmw

bornmw commented Oct 11, 2026

Copy link
Copy Markdown
Author

Fixed uncrustify issues
Locally installed one produces very different results, will need to figure out why

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

window-zoom: disabling the plugin crashes the session when a zoomed window has been closed (use-after-free in fini())

2 participants