Package: gnome-keyring
Version: 3.18.2-1
Severity: normal
Hi,
When I start gnome-session (not sure if startx is important to
reproduce) by
$ startx
Current gnome-keyring has the race with org.gnome.SessionManager
initialization of gnome-session. Because dbus doesn't seem to make the
name available to others immediately.
The sequence of the race is:
gnome-session gnome-keyring
.SessionManager init
run autostart apps
start by autostart
call .SessionManager.Setenv
call .SessionManager.ClientPrivate
.SessionManager available
This race becomes the cause of random Setenv failure for SSH_AUTH_SOCK
for example like following.
** Message: couldn't register in session:
GDBus.Error:org.freedesktop.DBus.Error.ServiceUnknown: The name
org.gnome.SessionManager was not provided by any .service files
To fix this, the attached patch starts to watch .NameOwnerChanged before
calling .SessionManager. With this, if .SessionManager is not available
yet, callings are done via .NameOwnerChanged notification.
Then, after makes sure calling of .SessionManager was done, this
removes watch of .NameOwnerChanged.
-- System Information:
Debian Release: stretch/sid
APT prefers testing-proposed-updates
APT policy: (500, 'testing-proposed-updates'), (500, 'testing')
Architecture: amd64 (x86_64)
Foreign Architectures: i386
Kernel: Linux 3.18.24 (SMP w/8 CPU cores)
Locale: LANG=ja_JP.UTF-8, LC_CTYPE=ja_JP.UTF-8 (charmap=UTF-8)
Shell: /bin/sh linked to /bin/bash
Init: sysvinit (via /sbin/init)
Versions of packages gnome-keyring depends on:
ii dbus-x11 1.10.2-1
ii dconf-gsettings-backend [gsettings-backend] 0.24.0-2
ii gcr 3.18.0-1
ii libc6 2.19-22
ii libcap-ng0 0.7.7-1
ii libcap2-bin 1:2.24-12
ii libgck-1-0 3.18.0-1
ii libgcr-base-3-1 3.18.0-1
ii libgcrypt20 1.6.4-3
ii libglib2.0-0 2.46.1-2
ii p11-kit 0.23.1-3
ii pinentry-gnome3 0.9.6-4
Versions of packages gnome-keyring recommends:
ii libpam-gnome-keyring 3.18.2-1
gnome-keyring suggests no packages.
-- no debconf information
--
OGAWA Hirofumi <[email protected]>
Current gnome-keyring has the race with org.gnome.SessionManager
initialization of gnome-session. Because dbus doesn't make the name
available to others immediately.
The sequence of the race is:
gnome-session gnome-keyring
.SessionManager init
run autostart apps
start by autostart
call .SessionManager.Setenv
call .SessionManager.ClientPrivate
.SessionManager available
This race becomes the cause of random Setenv failure for SSH_AUTH_SOCK
for example like following.
** Message: couldn't register in session: GDBus.Error:org.freedesktop.DBus.Error.ServiceUnknown: The name org.gnome.SessionManager was not provided by any .service files
To fix this, this starts to watch .NameOwnerChanged before calling
.SessionManager. With this, if .SessionManager is not available yet,
callings are done via .NameOwnerChanged notification.
Then, after makes sure calling of .SessionManager was done, this
removes watch of .NameOwnerChanged.
---
daemon/dbus/gkd-dbus-environment.c | 9 ++-
daemon/dbus/gkd-dbus-session.c | 89 ++++++++++++++++++++++++++++++++++--
daemon/dbus/gkd-dbus.c | 1
3 files changed, 92 insertions(+), 7 deletions(-)
diff -puN daemon/dbus/gkd-dbus-environment.c~session-race-fix daemon/dbus/gkd-dbus-environment.c
--- gnome-keyring-3.18.2/daemon/dbus/gkd-dbus-environment.c~session-race-fix 2015-10-29 20:37:32.812933216 +0900
+++ gnome-keyring-3.18.2-hirofumi/daemon/dbus/gkd-dbus-environment.c 2015-10-29 20:38:12.196871701 +0900
@@ -103,6 +103,7 @@ on_watch_environment (gpointer data, gpo
void
gkd_dbus_environment_init (GDBusConnection *conn)
{
+ static gboolean watch_installed = FALSE;
const gchar **envp;
/*
@@ -114,6 +115,10 @@ gkd_dbus_environment_init (GDBusConnecti
for (; *envp; ++envp)
setenv_request (conn, *envp);
- gkd_util_watch_environment (on_watch_environment, g_object_ref (conn),
- (GDestroyNotify) g_object_unref);
+ if (!watch_installed) {
+ watch_installed = TRUE;
+ gkd_util_watch_environment (on_watch_environment,
+ g_object_ref (conn),
+ (GDestroyNotify) g_object_unref);
+ }
}
diff -puN daemon/dbus/gkd-dbus-session.c~session-race-fix daemon/dbus/gkd-dbus-session.c
--- gnome-keyring-3.18.2/daemon/dbus/gkd-dbus-session.c~session-race-fix 2015-10-29 20:37:32.816933209 +0900
+++ gnome-keyring-3.18.2-hirofumi/daemon/dbus/gkd-dbus-session.c 2015-10-29 20:37:32.820933203 +0900
@@ -37,6 +37,9 @@
static gchar *client_session_path = NULL;
static guint client_session_signal_id = 0;
+static gboolean session_started = FALSE;
+static guint session_start_signal_id = 0;
+
static void
send_end_session_response (GDBusConnection *conn)
{
@@ -120,19 +123,29 @@ signal_filter (GDBusConnection *conn,
}
}
+static void session_start_cleanup (GDBusConnection *conn)
+{
+ if (session_start_signal_id == 0)
+ return;
+
+ g_dbus_connection_signal_unsubscribe (conn, session_start_signal_id);
+ session_start_signal_id = 0;
+}
+
void
gkd_dbus_session_cleanup (GDBusConnection *conn)
{
g_free (client_session_path);
client_session_path = NULL;
+ session_start_cleanup (conn);
}
/*
* Here we register our desktop autostart id gnome-session style
* session manager via DBus.
*/
-void
-gkd_dbus_session_init (GDBusConnection *conn)
+static gboolean
+gkd_dbus_session_client_init (GDBusConnection *conn)
{
const gchar *app_id = "gnome-keyring-daemon";
const gchar *client_id;
@@ -141,7 +154,7 @@ gkd_dbus_session_init (GDBusConnection *
client_id = g_getenv ("DESKTOP_AUTOSTART_ID");
if (!client_id)
- return;
+ return TRUE;
object_path_variant = g_dbus_connection_call_sync (conn,
SERVICE_SESSION_MANAGER,
@@ -156,9 +169,14 @@ gkd_dbus_session_init (GDBusConnection *
NULL, &error);
if (error != NULL) {
+ gboolean ret = TRUE;
+ /* SessionManager is not initialized yet, will restart later. */
+ if (g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_SERVICE_UNKNOWN))
+ ret = FALSE;
+
g_message ("couldn't register in session: %s", error->message);
g_error_free (error);
- return;
+ return ret;
}
g_variant_get (object_path_variant, "(o)", &client_session_path);
@@ -180,4 +198,67 @@ gkd_dbus_session_init (GDBusConnection *
client_session_path, NULL,
G_DBUS_SIGNAL_FLAGS_NONE,
signal_filter, NULL, NULL);
+
+ return TRUE;
+}
+
+static void session_start (GDBusConnection *conn)
+{
+ if (!session_started) {
+ if (gkd_dbus_session_client_init (conn)) {
+ gkd_dbus_environment_init (conn);
+ session_started = TRUE;
+ }
+ }
+}
+
+static void
+session_start_signal (GDBusConnection *conn,
+ const gchar *sender_name,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *signal_name,
+ GVariant *parameters,
+ gpointer user_data)
+{
+ const gchar *object_name;
+ const gchar *old_owner;
+ const gchar *new_owner;
+
+ if (session_started) {
+ /* Started already, so remove watch. */
+ session_start_cleanup (conn);
+ return;
+ }
+
+ g_variant_get (parameters, "(&s&s&s)", &object_name, &old_owner, &new_owner);
+ g_debug ("watch owner: \"%s\", \"%s\", \"%s\"",
+ object_name, old_owner, new_owner);
+ if (g_str_equal (object_name, SERVICE_SESSION_MANAGER) &&
+ new_owner[0] == ':') {
+ /* SessionManager has started. */
+ session_start (conn);
+ }
+}
+
+void
+gkd_dbus_session_init (GDBusConnection *conn)
+{
+ /*
+ * This is to fix the race with Session Manager initialization.
+ *
+ * So, this start to watch NameOwnerChanged, then session_start().
+ * With this order, we should never miss to initialize.
+ */
+ session_start_signal_id =
+ g_dbus_connection_signal_subscribe (conn,
+ NULL,
+ "org.freedesktop.DBus",
+ "NameOwnerChanged",
+ NULL, NULL,
+ G_DBUS_SIGNAL_FLAGS_NONE,
+ session_start_signal,
+ NULL, NULL);
+
+ session_start (conn);
}
diff -puN daemon/dbus/gkd-dbus.c~session-race-fix daemon/dbus/gkd-dbus.c
--- gnome-keyring-3.18.2/daemon/dbus/gkd-dbus.c~session-race-fix 2015-10-29 20:37:32.816933209 +0900
+++ gnome-keyring-3.18.2-hirofumi/daemon/dbus/gkd-dbus.c 2015-10-29 20:37:32.820933203 +0900
@@ -273,7 +273,6 @@ gkd_dbus_setup (void)
gkd_dbus_singleton_acquire (&unused);
/* Session stuff */
- gkd_dbus_environment_init (dbus_conn);
gkd_dbus_session_init (dbus_conn);
/* Secrets API */
_