[gvfs/wip/oholy/socket-fixes: 5/5] client: Prevent socket leaks if socket dir is inaccessible




commit 4d1d8e20315a1ac3e814742d79e4ced4257d1256
Author: Ondrej Holy <oholy redhat com>
Date:   Tue Mar 30 15:36:45 2021 +0200

    client: Prevent socket leaks if socket dir is inaccessible
    
    GVfs fallbacks to session bus if it is not possible to establish
    peer-to-peer connection (e.g. inside Flatpak sandbox). However,
    the DBus server is not terminated and the socket is leaked. The
    named sockets are counted as open files, so it can easily lead to
    "Too many open files" errors. Let's fallback to the session bus
    immediately if the socket dir is not accessible to prevent the
    leaks. This should fix the most common case, when the sockets are
    leaked.
    
    Fixes: https://gitlab.gnome.org/GNOME/gvfs/-/issues/542

 client/gvfsdaemondbus.c | 88 +++++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 75 insertions(+), 13 deletions(-)
---
diff --git a/client/gvfsdaemondbus.c b/client/gvfsdaemondbus.c
index f8deb097..f7b383a5 100644
--- a/client/gvfsdaemondbus.c
+++ b/client/gvfsdaemondbus.c
@@ -31,12 +31,14 @@
 #include <errno.h>
 
 #include <glib/gi18n-lib.h>
+#include <glib/gstdio.h>
 
 #include <gio/gio.h>
 #include "gvfsdaemondbus.h"
 #include <gvfsdaemonprotocol.h>
 #include <gdaemonvfs.h>
 #include <gvfsdbus.h>
+#include <gvfsutils.h>
 
 /* Extra vfs-specific data for GDBusConnections */
 typedef struct {
@@ -156,6 +158,7 @@ set_connection_for_async (GDBusConnection *connection, const char *dbus_id)
 typedef struct {
   char *dbus_id;
 
+  GVfsDBusDaemon *proxy;
   GDBusConnection *connection;
   GCancellable *cancellable;
 
@@ -174,6 +177,7 @@ async_call_finish (AsyncDBusCall *async_call)
                          async_call->io_error, 
                          async_call->callback_data);
 
+  g_clear_object (&async_call->proxy);
   g_clear_object (&async_call->connection);
   g_clear_object (&async_call->cancellable);
   g_clear_error (&async_call->io_error);
@@ -260,32 +264,67 @@ async_get_connection_response (GVfsDBusDaemon *proxy,
   g_free (address1);
 }
 
+static void
+socket_dir_query_info_cb (GObject *source_object,
+                          GAsyncResult *res,
+                          gpointer user_data)
+{
+  AsyncDBusCall *async_call = user_data;
+  g_autoptr (GFileInfo) socket_dir_info = NULL;
+
+  socket_dir_info = g_file_query_info_finish (G_FILE (source_object),
+                                              res,
+                                              &async_call->io_error);
+  if (socket_dir_info == NULL ||
+      !g_file_info_get_attribute_boolean (socket_dir_info,
+                                          G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE))
+    {
+      if (!async_call->io_error)
+        async_call->io_error = g_error_new_literal (G_IO_ERROR,
+                                                    G_IO_ERROR_PERMISSION_DENIED,
+                                                    _("Permission denied"));
+
+      async_call_finish (async_call);
+      return;
+    }
+
+  g_dbus_proxy_set_default_timeout (G_DBUS_PROXY (async_call->proxy), G_VFS_DBUS_TIMEOUT_MSECS);
+
+  gvfs_dbus_daemon_call_get_connection (async_call->proxy,
+                                        async_call->cancellable,
+                                        (GAsyncReadyCallback) async_get_connection_response,
+                                        async_call);
+}
+
 static void
 open_connection_async_cb (GObject *source_object,
                           GAsyncResult *res,
                           gpointer user_data)
 {
-  GVfsDBusDaemon *proxy;
   AsyncDBusCall *async_call = user_data;
   GError *error = NULL;
- 
-  proxy = gvfs_dbus_daemon_proxy_new_finish (res, &error);
-  if (proxy == NULL)
+  g_autofree gchar *socket_dir_path = NULL;
+  g_autoptr (GFile) socket_dir = NULL;
+
+  async_call->proxy = gvfs_dbus_daemon_proxy_new_finish (res, &error);
+  if (async_call->proxy == NULL)
     {
       async_call->io_error = g_error_copy (error);
       g_error_free (error);
       async_call_finish (async_call);
       return;
     }
-  
-  g_dbus_proxy_set_default_timeout (G_DBUS_PROXY (proxy), G_VFS_DBUS_TIMEOUT_MSECS);
-  
-  gvfs_dbus_daemon_call_get_connection (proxy,
-                                        async_call->cancellable,
-                                        (GAsyncReadyCallback) async_get_connection_response,
-                                        async_call);
-  
-  g_object_unref (proxy);
+
+  /* This is needed to prevent socket leaks. */
+  socket_dir_path = gvfs_get_socket_dir ();
+  socket_dir = g_file_new_for_path (socket_dir_path);
+  g_file_query_info_async (socket_dir,
+                           G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE,
+                           G_FILE_QUERY_INFO_NONE,
+                           G_PRIORITY_DEFAULT,
+                           async_call->cancellable,
+                           socket_dir_query_info_cb,
+                           user_data);
 }
 
 static void
@@ -522,6 +561,9 @@ _g_dbus_connection_get_sync (const char *dbus_id,
   gchar *address1;
   GVfsDBusDaemon *daemon_proxy;
   gboolean res;
+  g_autofree gchar *socket_dir_path = NULL;
+  g_autoptr (GFile) socket_dir = NULL;
+  g_autoptr (GFileInfo) socket_dir_info = NULL;
 
   if (g_cancellable_set_error_if_cancelled (cancellable, error))
     return NULL;
@@ -591,6 +633,26 @@ _g_dbus_connection_get_sync (const char *dbus_id,
   if (daemon_proxy == NULL)
     return NULL;
 
+  /* This is needed to prevent socket leaks. */
+  socket_dir_path = gvfs_get_socket_dir ();
+  socket_dir = g_file_new_for_path (socket_dir_path);
+  socket_dir_info = g_file_query_info (socket_dir,
+                                       G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE,
+                                       G_FILE_QUERY_INFO_NONE,
+                                       cancellable,
+                                       error);
+  if (socket_dir_info == NULL ||
+      !g_file_info_get_attribute_boolean (socket_dir_info,
+                                          G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE))
+    {
+      if (error && !*error)
+        *error = g_error_new_literal (G_IO_ERROR,
+                                      G_IO_ERROR_PERMISSION_DENIED,
+                                      _("Permission denied"));
+
+      return NULL;
+    }
+
   address1 = NULL;
   res = gvfs_dbus_daemon_call_get_connection_sync (daemon_proxy,
                                                    &address1,


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