Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
xwayland: fix use-after-free in selection handling
Fixes swaywm#2425. wlroots can only handle one outgoing transfer at a time, so it keeps a list of pending selections. The head of the list is the currently-active selection, and when that transfer completes and is destroyed, the next one is started. The trouble is when you have a transfer to some app that is misbehaving. fcitx is one such application. With really large transfers, fcitx will hang and never wake up again. So, you can end up with a transfer list that looks like this: | swaywm#1: started | swaywm#2: pending | swaywm#3: pending | swaywm#4: pending | The file descriptor for transfer swaywm#1 is registered in libwayland's epoll loop. The rest are waiting in wlroots' list. As a user, you want your clipboard back, so you `pkill fcitx`. Now Xwayland sends `XCB_DESTROY_NOTIFY` to let us know to give up. We clean up swaywm#4 first. Due to a bug in wlroots code, we register the (fd, transfer data pointer) pair for swaywm#1 with libwayland *again*, despite it already being registered. We do this 2 more times as we remove swaywm#3 and swaywm#2. Finally, we remove swaywm#1 and `free` all the memory associated with it, before `close`-ing its transfer file descriptor. However, we still have 3 copies of swaywm#1's file descriptor left in the epoll loop, since we erroneously added them as part of removing swaywm#2/3/4. When we `close` the file descriptor as part of swaywm#1's teardown, we actually cause the epoll loop to wake up the next time around, saying "this file descriptor has activity!" (it was closed, so `read`-ing would normally return 0 to let us know of EOF). But instead of returning 0, it returns -1 with `EBADF`, because the file descriptor has already been closed. And finally, as part of error-handling this, we access the transfer pointer, which was `free`'d. And we crash.
- Loading branch information