[mutter] remote-desktop: Check pipe fd before assuming existing read() operation



commit 20db6af4e6b7aaaa49ac27aa6041f5c47d157325
Author: Pascal Nowack <Pascal Nowack gmx de>
Date:   Tue May 25 11:07:40 2021 +0200

    remote-desktop: Check pipe fd before assuming existing read() operation
    
    Currently, if g-r-d closes the read end of the pipe for a
    SelectionRead() operation, due to realizing that the application, that
    should provide the mime type content, does not provide any content,
    mutter won't notice that and still assumes that the read() operation
    on the pipe in g-r-d is still happening, as mutter never writes to the
    pipe in that situation and therefore cannot realize that the pipe is
    already closed.
    The effect of this is, that if g-r-d aborts a read() operation and
    requests a new read() operation via SelectionRead(), mutter will deny
    the request since it assumes that the previous read() operation is
    still ongoing.
    
    Fix this behaviour by also checking the pipe fd in mutter before
    denying a SelectionRead() request.
    
    https://gitlab.gnome.org/GNOME/gnome-remote-desktop/-/issues/60
    
    Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1874>

 src/backends/meta-remote-desktop-session.c | 43 +++++++++++++++++++++++++++++-
 1 file changed, 42 insertions(+), 1 deletion(-)
---
diff --git a/src/backends/meta-remote-desktop-session.c b/src/backends/meta-remote-desktop-session.c
index e15bd63de6..caee7aa6a7 100644
--- a/src/backends/meta-remote-desktop-session.c
+++ b/src/backends/meta-remote-desktop-session.c
@@ -1467,6 +1467,47 @@ handle_selection_write_done (MetaDBusRemoteDesktopSession *skeleton,
   return TRUE;
 }
 
+static gboolean
+is_pipe_broken (int fd)
+{
+  GPollFD poll_fd = {0};
+  int poll_ret;
+  int errsv;
+
+  poll_fd.fd = fd;
+  poll_fd.events = G_IO_OUT;
+
+  do
+    {
+      poll_ret = g_poll (&poll_fd, 1, 0);
+      errsv = errno;
+    }
+  while (poll_ret == -1 && errsv == EINTR);
+
+  if (poll_ret < 0)
+    return FALSE;
+
+  return !!(poll_fd.revents & G_IO_ERR);
+}
+
+static gboolean
+has_pending_read_operation (SelectionReadData *read_data)
+{
+  int fd;
+
+  if (!read_data)
+    return FALSE;
+
+  fd = g_unix_output_stream_get_fd (G_UNIX_OUTPUT_STREAM (read_data->stream));
+  if (is_pipe_broken (fd))
+    {
+      cancel_selection_read (read_data->session);
+      return FALSE;
+    }
+
+  return TRUE;
+}
+
 static void
 transfer_cb (MetaSelection     *selection,
              GAsyncResult      *res,
@@ -1544,7 +1585,7 @@ handle_selection_read (MetaDBusRemoteDesktopSession *skeleton,
       return TRUE;
     }
 
-  if (session->read_data)
+  if (has_pending_read_operation (session->read_data))
     {
       g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
                                              G_DBUS_ERROR_LIMITS_EXCEEDED,


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]