summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOndrej Holy <oholy@redhat.com>2021-03-30 15:36:45 +0200
committerOndrej Holy <oholy@redhat.com>2021-03-31 15:56:59 +0200
commit4d1d8e20315a1ac3e814742d79e4ced4257d1256 (patch)
treec9b66551c60fdfc1d8b3e2881a730018998c62de
parent09733ddc402fe3999ac323d8d4cbddd938659016 (diff)
downloadgvfs-wip/oholy/admin-fixes.tar.gz
client: Prevent socket leaks if socket dir is inaccessiblewip/oholy/admin-fixes
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,