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 <hirof...@mail.parknet.co.jp>


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 */
_

Reply via email to