mirror of
https://gitlab.freedesktop.org/xorg/xserver.git
synced 2026-05-05 02:58:06 +02:00
xwayland: Monitor client states to destroy callbacks
In XWayland, dri3_send_open_reply() is called from a sync callback, so
there is a possibility that the client might be gone when we get to the
callback eventually, which leads to a crash in _XSERVTransSendFd() from
WriteFdToClient() .
Client resources can survive the client itself, in which case we
may end up in our sync callback trying to access client's data after
it's been freed/reclaimed.
Add a ClientStateCallback handler to monitor the client state changes
and clear the sync callback set up by the glamor drm code if any.
Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1416553
Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=100040
Tested-by: Mark B <mark.blakeney@bullet-systems.net>
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Reviewed-by: Michel Dänzer <michel.daenzer@amd.com>
(cherry picked from commit 937527f979)
This commit is contained in:
parent
d402b86b45
commit
18fcb66688
1 changed files with 51 additions and 7 deletions
|
|
@ -38,6 +38,8 @@
|
|||
#include <dri3.h>
|
||||
#include "drm-client-protocol.h"
|
||||
|
||||
static DevPrivateKeyRec xwl_auth_state_private_key;
|
||||
|
||||
struct xwl_pixmap {
|
||||
struct wl_buffer *buffer;
|
||||
struct gbm_bo *bo;
|
||||
|
|
@ -429,17 +431,49 @@ glamor_egl_dri3_fd_name_from_tex(ScreenPtr screen,
|
|||
struct xwl_auth_state {
|
||||
int fd;
|
||||
ClientPtr client;
|
||||
struct wl_callback *callback;
|
||||
};
|
||||
|
||||
static void
|
||||
free_xwl_auth_state(ClientPtr pClient, struct xwl_auth_state *state)
|
||||
{
|
||||
dixSetPrivate(&pClient->devPrivates, &xwl_auth_state_private_key, NULL);
|
||||
if (state) {
|
||||
wl_callback_destroy(state->callback);
|
||||
free(state);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
xwl_auth_state_client_callback(CallbackListPtr *pcbl, void *unused, void *data)
|
||||
{
|
||||
NewClientInfoRec *clientinfo = (NewClientInfoRec *) data;
|
||||
ClientPtr pClient = clientinfo->client;
|
||||
struct xwl_auth_state *state;
|
||||
|
||||
switch (pClient->clientState) {
|
||||
case ClientStateGone:
|
||||
case ClientStateRetained:
|
||||
state = dixLookupPrivate(&pClient->devPrivates, &xwl_auth_state_private_key);
|
||||
free_xwl_auth_state(pClient, state);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sync_callback(void *data, struct wl_callback *callback, uint32_t serial)
|
||||
{
|
||||
struct xwl_auth_state *state = data;
|
||||
ClientPtr client = state->client;
|
||||
|
||||
dri3_send_open_reply(state->client, state->fd);
|
||||
AttendClient(state->client);
|
||||
free(state);
|
||||
wl_callback_destroy(callback);
|
||||
/* if the client is gone, the callback is cancelled so it's safe to
|
||||
* assume the client is still in ClientStateRunning at this point...
|
||||
*/
|
||||
dri3_send_open_reply(client, state->fd);
|
||||
AttendClient(client);
|
||||
free_xwl_auth_state(client, state);
|
||||
}
|
||||
|
||||
static const struct wl_callback_listener sync_listener = {
|
||||
|
|
@ -454,7 +488,6 @@ xwl_dri3_open_client(ClientPtr client,
|
|||
{
|
||||
struct xwl_screen *xwl_screen = xwl_screen_get(screen);
|
||||
struct xwl_auth_state *state;
|
||||
struct wl_callback *callback;
|
||||
drm_magic_t magic;
|
||||
int fd;
|
||||
|
||||
|
|
@ -482,8 +515,9 @@ xwl_dri3_open_client(ClientPtr client,
|
|||
}
|
||||
|
||||
wl_drm_authenticate(xwl_screen->drm, magic);
|
||||
callback = wl_display_sync(xwl_screen->display);
|
||||
wl_callback_add_listener(callback, &sync_listener, state);
|
||||
state->callback = wl_display_sync(xwl_screen->display);
|
||||
wl_callback_add_listener(state->callback, &sync_listener, state);
|
||||
dixSetPrivate(&client->devPrivates, &xwl_auth_state_private_key, state);
|
||||
|
||||
IgnoreClient(client);
|
||||
|
||||
|
|
@ -565,6 +599,16 @@ xwl_glamor_init(struct xwl_screen *xwl_screen)
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
if (!dixRegisterPrivateKey(&xwl_auth_state_private_key, PRIVATE_CLIENT, 0)) {
|
||||
ErrorF("Failed to register private key\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!AddCallback(&ClientStateCallback, xwl_auth_state_client_callback, NULL)) {
|
||||
ErrorF("Failed to add client state callback\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
xwl_screen->CreateScreenResources = screen->CreateScreenResources;
|
||||
screen->CreateScreenResources = xwl_glamor_create_screen_resources;
|
||||
screen->CreatePixmap = xwl_glamor_create_pixmap;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue