summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOndrej Holy <oholy@redhat.com>2021-03-30 15:36:45 +0200
committerOndrej Holy <oholy@redhat.com>2021-04-15 07:12:32 +0000
commitc615cfe11f58e72e92dc5bb2dc14adc702d05200 (patch)
tree54f96a0d9ee63294157fda0196dd2d2ce5e1a71e
parent117d5318ac01858a0ee922c1e8a5d83fde9b3670 (diff)
downloadgvfs-c615cfe11f58e72e92dc5bb2dc14adc702d05200.tar.gz
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
-rw-r--r--client/gvfsdaemondbus.c88
1 files 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);
@@ -261,31 +265,66 @@ async_get_connection_response (GVfsDBusDaemon *proxy,
}
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,