diff options
author | Tudor Brindus <me@tbrindus.ca> | 2021-01-29 19:00:17 -0500 |
---|---|---|
committer | Simon Ser <contact@emersion.fr> | 2021-01-31 10:24:59 +0100 |
commit | b6ba595862a55e5e2899d4c38dd22a1f8ffcabaa (patch) | |
tree | 76988b43a8127bd2d9df65af5c79c085234ec95f /xwayland/selection | |
parent | 3417fc0cca8d392d0154012b3fd8149e71f25c6d (diff) |
xwayland/selection: destroy all selections on Xwayland restart
Previously, Xwayland could restart, and we'd get events for transfers
pointing to the previous (now freed) xwm instance. This led to
use-after-free segfaults.
Closes #2565.
Diffstat (limited to 'xwayland/selection')
-rw-r--r-- | xwayland/selection/outgoing.c | 2 | ||||
-rw-r--r-- | xwayland/selection/selection.c | 26 |
2 files changed, 25 insertions, 3 deletions
diff --git a/xwayland/selection/outgoing.c b/xwayland/selection/outgoing.c index 8d011729..1e490adb 100644 --- a/xwayland/selection/outgoing.c +++ b/xwayland/selection/outgoing.c @@ -66,7 +66,7 @@ static struct wlr_xwm_selection_transfer *xwm_selection_transfer_get_first( return first; } -static void xwm_selection_transfer_destroy_outgoing( +void xwm_selection_transfer_destroy_outgoing( struct wlr_xwm_selection_transfer *transfer) { struct wlr_xwm_selection *selection = transfer->selection; bool was_first = transfer == xwm_selection_transfer_get_first(selection); diff --git a/xwayland/selection/selection.c b/xwayland/selection/selection.c index ea0910d7..a6042582 100644 --- a/xwayland/selection/selection.c +++ b/xwayland/selection/selection.c @@ -249,25 +249,47 @@ void xwm_selection_finish(struct wlr_xwm *xwm) { if (!xwm) { return; } + + struct wlr_xwm_selection *selections[] = { + &xwm->clipboard_selection, + &xwm->primary_selection, + &xwm->dnd_selection, + }; + + for (size_t i = 0; i < sizeof(selections)/sizeof(selections[0]); i++) { + struct wlr_xwm_selection *selection = selections[i]; + + struct wlr_xwm_selection_transfer *outgoing, *tmp; + wl_list_for_each_safe(outgoing, tmp, &selection->outgoing, outgoing_link) { + wlr_log(WLR_INFO, "destroyed pending transfer %ld/%p", i, outgoing); + xwm_selection_transfer_destroy_outgoing(outgoing); + } + + xwm_selection_transfer_finish(&selection->incoming); + } + if (xwm->selection_window) { xcb_destroy_window(xwm->xcb_conn, xwm->selection_window); } + if (xwm->dnd_window) { xcb_destroy_window(xwm->xcb_conn, xwm->dnd_window); } + if (xwm->seat) { if (xwm->seat->selection_source && - data_source_is_xwayland( - xwm->seat->selection_source)) { + data_source_is_xwayland(xwm->seat->selection_source)) { wlr_seat_set_selection(xwm->seat, NULL, wl_display_next_serial(xwm->xwayland->wl_display)); } + if (xwm->seat->primary_selection_source && primary_selection_source_is_xwayland( xwm->seat->primary_selection_source)) { wlr_seat_set_primary_selection(xwm->seat, NULL, wl_display_next_serial(xwm->xwayland->wl_display)); } + wlr_xwayland_set_seat(xwm->xwayland, NULL); } } |