From dcf716945f45118dff57631daf4a6d60095e5c84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Barnab=C3=A1=20Silva?= Date: Wed, 29 Oct 2025 02:38:00 -0300 Subject: [PATCH] gdbusserver: retry binding to unix addresses only when possible This adds the condition that a new unix address is tried only when there is enough space to append random character(s) before the address reach the length of UNIX_PATH_MAX. Before this change, creating a GDBusServer with unix addresses longer than UNIX_PATH_MAX that existed in the filesystem would never return. A test that expects G_IO_ERROR_ADDRESS_IN_USE in such scenario was added. --- gio/gdbusserver.c | 15 ++++++++++-- gio/tests/gdbus-server-auth.c | 45 +++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 2 deletions(-) diff --git a/gio/gdbusserver.c b/gio/gdbusserver.c index e4ef69df0..23b75a959 100644 --- a/gio/gdbusserver.c +++ b/gio/gdbusserver.c @@ -45,12 +45,14 @@ #include "ginputstream.h" #include "giostream.h" #include "gmarshal-internal.h" +#include "gnetworking.h" #ifdef G_OS_UNIX #include #endif #ifdef G_OS_WIN32 #include +#include "giowin32-afunix.h" #endif #include "gunixsocketaddress.h" @@ -62,6 +64,10 @@ G_DBUS_SERVER_FLAGS_AUTHENTICATION_ALLOW_ANONYMOUS | \ G_DBUS_SERVER_FLAGS_AUTHENTICATION_REQUIRE_SAME_USER) +#ifndef UNIX_PATH_MAX +#define UNIX_PATH_MAX G_SIZEOF_MEMBER (struct sockaddr_un, sun_path) +#endif + /** * GDBusServer: * @@ -699,10 +705,12 @@ try_unix (GDBusServer *server, gint n; GString *s; GError *local_error; + gsize orig_path_len = 0; // length before random characters are added retry: s = g_string_new (tmpdir != NULL ? tmpdir : dir); g_string_append (s, "/dbus-"); + orig_path_len = s->len; for (n = 0; n < 8; n++) g_string_append_c (s, random_ascii ()); @@ -720,8 +728,11 @@ try_unix (GDBusServer *server, { if (local_error->domain == G_IO_ERROR && local_error->code == G_IO_ERROR_ADDRESS_IN_USE) { - g_error_free (local_error); - goto retry; + if (orig_path_len < UNIX_PATH_MAX - 2) /* random_ascii + NULL byte */ + { + g_error_free (local_error); + goto retry; + } } g_propagate_error (error, local_error); goto out; diff --git a/gio/tests/gdbus-server-auth.c b/gio/tests/gdbus-server-auth.c index 319a9948b..b96ab961f 100644 --- a/gio/tests/gdbus-server-auth.c +++ b/gio/tests/gdbus-server-auth.c @@ -537,6 +537,50 @@ test_server_auth_sha1_tcp (void) do_test_server_auth (INTEROP_FLAGS_SHA1 | INTEROP_FLAGS_TCP); } +static void +test_server_path_in_use (void) +{ +#ifdef G_OS_UNIX +#ifndef UNIX_PATH_MAX +#define UNIX_PATH_MAX G_SIZEOF_MEMBER (struct sockaddr_un, sun_path) +#endif + GError *error = NULL; + GString *path = NULL; + gchar *listenable_address = NULL; + GDBusServer *server = NULL; + gchar *guid = NULL; + gchar *escaped = NULL; + + path = g_string_new (g_get_tmp_dir ()); + guid = g_dbus_generate_guid (); + while (path->len < UNIX_PATH_MAX - 1) + g_string_append_c (path, 'x'); + escaped = g_dbus_address_escape_value (path->str); + listenable_address = g_strdup_printf ("unix:%s=%s", "dir", escaped); + g_assert_cmpint (g_mkdir_with_parents (path->str, 0700), ==, 0); + g_string_free (path, TRUE); + + server = g_dbus_server_new_sync (listenable_address, + G_DBUS_SERVER_FLAGS_RUN_IN_THREAD, + guid, + NULL, + NULL, + &error); + g_assert_error (error, G_IO_ERROR, G_IO_ERROR_ADDRESS_IN_USE); + g_error_free (error); + + if (server != NULL) + g_dbus_server_stop (server); + + g_clear_object (&server); + g_free (guid); + g_free (escaped); + g_free (listenable_address); +#else + g_test_skip ("unix: addresses only work on Unix"); +#endif +} + int main (int argc, char *argv[]) @@ -552,6 +596,7 @@ main (int argc, g_test_add_func ("/gdbus/server-auth/external/require-same-user", test_server_auth_external_require_same_user); g_test_add_func ("/gdbus/server-auth/sha1", test_server_auth_sha1); g_test_add_func ("/gdbus/server-auth/sha1/tcp", test_server_auth_sha1_tcp); + g_test_add_func ("/gdbus/server-auth/path-in-use", test_server_path_in_use); return g_test_run(); }