From b6ba595862a55e5e2899d4c38dd22a1f8ffcabaa Mon Sep 17 00:00:00 2001 From: Tudor Brindus Date: Fri, 29 Jan 2021 19:00:17 -0500 Subject: [PATCH] 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. --- include/xwayland/selection.h | 3 +++ xwayland/selection/outgoing.c | 2 +- xwayland/selection/selection.c | 26 ++++++++++++++++++++++++-- 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/include/xwayland/selection.h b/include/xwayland/selection.h index 5e65e8bb..3f00fd54 100644 --- a/include/xwayland/selection.h +++ b/include/xwayland/selection.h @@ -51,6 +51,9 @@ void xwm_selection_transfer_finish(struct wlr_xwm_selection_transfer *transfer); bool xwm_selection_transfer_get_selection_property( struct wlr_xwm_selection_transfer *transfer, bool delete); +void xwm_selection_transfer_destroy_outgoing( + struct wlr_xwm_selection_transfer *transfer); + xcb_atom_t xwm_mime_type_to_atom(struct wlr_xwm *xwm, char *mime_type); char *xwm_mime_type_from_atom(struct wlr_xwm *xwm, xcb_atom_t atom); struct wlr_xwm_selection *xwm_get_selection(struct wlr_xwm *xwm, 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); } }