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.
This commit is contained in:
André Barnabá Silva
2025-10-29 02:38:00 -03:00
parent a4962ca460
commit dcf716945f
2 changed files with 58 additions and 2 deletions

View File

@@ -45,12 +45,14 @@
#include "ginputstream.h" #include "ginputstream.h"
#include "giostream.h" #include "giostream.h"
#include "gmarshal-internal.h" #include "gmarshal-internal.h"
#include "gnetworking.h"
#ifdef G_OS_UNIX #ifdef G_OS_UNIX
#include <unistd.h> #include <unistd.h>
#endif #endif
#ifdef G_OS_WIN32 #ifdef G_OS_WIN32
#include <io.h> #include <io.h>
#include "giowin32-afunix.h"
#endif #endif
#include "gunixsocketaddress.h" #include "gunixsocketaddress.h"
@@ -62,6 +64,10 @@
G_DBUS_SERVER_FLAGS_AUTHENTICATION_ALLOW_ANONYMOUS | \ G_DBUS_SERVER_FLAGS_AUTHENTICATION_ALLOW_ANONYMOUS | \
G_DBUS_SERVER_FLAGS_AUTHENTICATION_REQUIRE_SAME_USER) 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: * GDBusServer:
* *
@@ -699,10 +705,12 @@ try_unix (GDBusServer *server,
gint n; gint n;
GString *s; GString *s;
GError *local_error; GError *local_error;
gsize orig_path_len = 0; // length before random characters are added
retry: retry:
s = g_string_new (tmpdir != NULL ? tmpdir : dir); s = g_string_new (tmpdir != NULL ? tmpdir : dir);
g_string_append (s, "/dbus-"); g_string_append (s, "/dbus-");
orig_path_len = s->len;
for (n = 0; n < 8; n++) for (n = 0; n < 8; n++)
g_string_append_c (s, random_ascii ()); 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) if (local_error->domain == G_IO_ERROR && local_error->code == G_IO_ERROR_ADDRESS_IN_USE)
{ {
g_error_free (local_error); if (orig_path_len < UNIX_PATH_MAX - 2) /* random_ascii + NULL byte */
goto retry; {
g_error_free (local_error);
goto retry;
}
} }
g_propagate_error (error, local_error); g_propagate_error (error, local_error);
goto out; goto out;

View File

@@ -537,6 +537,50 @@ test_server_auth_sha1_tcp (void)
do_test_server_auth (INTEROP_FLAGS_SHA1 | INTEROP_FLAGS_TCP); 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 int
main (int argc, main (int argc,
char *argv[]) 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/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", 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/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(); return g_test_run();
} }