xwayland/selection: ignore requests for anything but the newest data

Our internal state machine gets screwed up if selection events are not
monotonically increasing in time, and we can enter a self-copy loop from
the proxy window that exhausts all pipes.

Snippet of logs when this occurs:

  00:00:46.238 [wlr] [xwayland/selection/incoming.c:487] XCB_XFIXES_SELECTION_NOTIFY (selection=277, owner=4194626)
  00:00:46.238 [wlr] [xwayland/selection/incoming.c:487] XCB_XFIXES_SELECTION_NOTIFY (selection=277, owner=2097153)
  00:00:46.238 [wlr] [xwayland/selection/outgoing.c:378] XCB_SELECTION_REQUEST (time=58979563 owner=2097153, requestor=2097153 selection=277, target=279, property=278)
  00:00:46.238 [wlr] [xwayland/selection/outgoing.c:397] ignoring old request from timestamp 58979563; expecting > 58979563
  00:00:46.238 [wlr] [xwayland/selection/outgoing.c:29] SendEvent destination=2097153 SelectionNotify(31) time=58979563 requestor=2097153 selection=277 target=279 property=0
  00:00:46.238 [wlr] [xwayland/selection/incoming.c:453] XCB_SELECTION_NOTIFY (selection=277, property=0, target=279)

Note that 2097153 is `selection->window`, and 4194626 is Emacs.

The race occurs if the selection owner changes back to our proxy window
between when we get `XCB_XFIXES_SELECTION_NOTIFY` for Emacs and when we
call `xcb_convert_selection` in `incoming.c:source_send` -- the
ConvertSelection request can end up hitting our proxy window, but the
timestamp will be rejected.

Fixes #2192.
This commit is contained in:
Tudor Brindus 2021-02-10 20:42:18 -05:00 committed by Simon Ser
parent 4a9e70ccde
commit 7d52b4d0b5

View file

@ -392,11 +392,24 @@ void xwm_handle_selection_request(struct wlr_xwm *xwm,
goto fail_notify_requestor;
}
if (selection->window != req->owner) {
wlr_log(WLR_DEBUG, "received selection request with invalid owner");
if (req->requestor == selection->window) {
wlr_log(WLR_ERROR, "selection request should have been caught before");
goto fail_notify_requestor;
}
if (selection->window != req->owner) {
if (req->time != XCB_CURRENT_TIME && req->time < selection->timestamp) {
wlr_log(WLR_DEBUG, "ignored old request from timestamp %d; expected > %d",
req->time, selection->timestamp);
goto fail_notify_requestor;
}
wlr_log(WLR_DEBUG, "received selection request with invalid owner");
// Don't fail (`goto fail_notify_requestor`) the selection request if we're
// no longer the selection owner.
return;
}
// No xwayland surface focused, deny access to clipboard
if (xwm->focus_surface == NULL && xwm->drag_focus == NULL) {
char *selection_name = xwm_get_atom_name(xwm, selection->atom);