aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTudor Brindus <me@tbrindus.ca>2021-01-29 19:00:17 -0500
committerSimon Ser <contact@emersion.fr>2021-01-31 10:24:59 +0100
commitb6ba595862a55e5e2899d4c38dd22a1f8ffcabaa (patch)
tree76988b43a8127bd2d9df65af5c79c085234ec95f
parent3417fc0cca8d392d0154012b3fd8149e71f25c6d (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.
-rw-r--r--include/xwayland/selection.h3
-rw-r--r--xwayland/selection/outgoing.c2
-rw-r--r--xwayland/selection/selection.c26
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);
}
}