Blob Blame History Raw
From 7d4eed356eb8a9a87f49d49405ab506271178968 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Mon, 14 Sep 2020 16:20:09 -0400
Subject: [PATCH 1/3] manager: Don't leak session objects

The first is from create_user_session_for display.  Most callers don't
check the return value, so it should just be void.

The user data associated with the session also isn't unlinked from the
display when the display is finishing up, preventing the display and
session object from getting freed.

This commit makes both changes.
---
 daemon/gdm-manager.c | 17 +++++++++--------
 1 file changed, 9 insertions(+), 8 deletions(-)

diff --git a/daemon/gdm-manager.c b/daemon/gdm-manager.c
index 66f814a6e..8f9be10ef 100644
--- a/daemon/gdm-manager.c
+++ b/daemon/gdm-manager.c
@@ -94,63 +94,63 @@ struct GdmManagerPrivate
 #ifdef  WITH_PLYMOUTH
         guint                     plymouth_is_running : 1;
 #endif
         guint                     ran_once : 1;
 };
 
 enum {
         PROP_0,
         PROP_XDMCP_ENABLED,
         PROP_SHOW_LOCAL_GREETER
 };
 
 enum {
         DISPLAY_ADDED,
         DISPLAY_REMOVED,
         LAST_SIGNAL
 };
 
 typedef enum {
         SESSION_RECORD_LOGIN,
         SESSION_RECORD_LOGOUT,
         SESSION_RECORD_FAILED,
 } SessionRecord;
 
 static guint signals [LAST_SIGNAL] = { 0, };
 
 static void     gdm_manager_class_init  (GdmManagerClass *klass);
 static void     gdm_manager_init        (GdmManager      *manager);
 static void     gdm_manager_dispose     (GObject         *object);
 
-static GdmSession *create_user_session_for_display (GdmManager *manager,
-                                                    GdmDisplay *display,
-                                                    uid_t       allowed_user);
+static void     create_user_session_for_display (GdmManager *manager,
+                                                 GdmDisplay *display,
+                                                 uid_t       allowed_user);
 static void     start_user_session (GdmManager                *manager,
                                     StartUserSessionOperation *operation);
 static void     clean_user_session (GdmSession *session);
 
 static gpointer manager_object = NULL;
 
 static void manager_interface_init (GdmDBusManagerIface *interface);
 
 G_DEFINE_TYPE_WITH_CODE (GdmManager,
                          gdm_manager,
                          GDM_DBUS_TYPE_MANAGER_SKELETON,
                          G_IMPLEMENT_INTERFACE (GDM_DBUS_TYPE_MANAGER,
                                                 manager_interface_init));
 
 #ifdef WITH_PLYMOUTH
 static gboolean
 plymouth_is_running (void)
 {
         int      status;
         gboolean res;
         GError  *error;
 
         error = NULL;
         res = g_spawn_command_line_sync ("/bin/plymouth --ping",
                                          NULL, NULL, &status, &error);
         if (! res) {
                 g_debug ("Could not ping plymouth: %s", error->message);
                 g_error_free (error);
                 return FALSE;
         }
@@ -1466,61 +1466,62 @@ out:
 }
 
 static const char *
 get_username_for_greeter_display (GdmManager *manager,
                                   GdmDisplay *display)
 {
         gboolean doing_initial_setup = FALSE;
 
         g_object_get (G_OBJECT (display),
                       "doing-initial-setup", &doing_initial_setup,
                       NULL);
 
         if (doing_initial_setup) {
                 return INITIAL_SETUP_USERNAME;
         } else {
                 return GDM_USERNAME;
         }
 }
 
 static void
 set_up_automatic_login_session (GdmManager *manager,
                                 GdmDisplay *display)
 {
         GdmSession *session;
         char       *display_session_type = NULL;
         gboolean is_initial;
 
         /* 0 is root user; since the daemon talks to the session object
          * directly, itself, for automatic login
          */
-        session = create_user_session_for_display (manager, display, 0);
+        create_user_session_for_display (manager, display, 0);
+        session = get_user_session_for_display (display);
 
         g_object_get (G_OBJECT (display),
                       "is-initial", &is_initial,
                       "session-type", &display_session_type,
                       NULL);
 
         g_object_set (G_OBJECT (session),
                       "display-is-initial", is_initial,
                       NULL);
 
         g_debug ("GdmManager: Starting automatic login conversation");
         gdm_session_start_conversation (session, "gdm-autologin");
 }
 
 static void
 set_up_chooser_session (GdmManager *manager,
                         GdmDisplay *display)
 {
         const char *allowed_user;
         struct passwd *passwd_entry;
 
         allowed_user = get_username_for_greeter_display (manager, display);
 
         if (!gdm_get_pwent_for_name (allowed_user, &passwd_entry)) {
                 g_warning ("GdmManager: couldn't look up username %s",
                            allowed_user);
                 gdm_display_unmanage (display);
                 gdm_display_finish (display);
                 return;
         }
@@ -1682,60 +1683,62 @@ on_display_status_changed (GdmDisplay *display,
 
         switch (status) {
                 case GDM_DISPLAY_PREPARED:
                 case GDM_DISPLAY_MANAGED:
                         if ((display_number == -1 && status == GDM_DISPLAY_PREPARED) ||
                             (display_number != -1 && status == GDM_DISPLAY_MANAGED)) {
                                 char *session_class;
 
                                 g_object_get (display,
                                               "session-class", &session_class,
                                               NULL);
                                 if (g_strcmp0 (session_class, "greeter") == 0)
                                         set_up_session (manager, display);
                                 g_free (session_class);
                         }
 
                         if (status == GDM_DISPLAY_MANAGED) {
                                 greeter_display_started (manager, display);
                         }
                         break;
                 case GDM_DISPLAY_FAILED:
                 case GDM_DISPLAY_UNMANAGED:
                 case GDM_DISPLAY_FINISHED:
 #ifdef WITH_PLYMOUTH
                         if (quit_plymouth) {
                                 plymouth_quit_without_transition ();
                                 manager->priv->plymouth_is_running = FALSE;
                         }
 #endif
 
+                        g_object_set_data (G_OBJECT (display), "gdm-user-session", NULL);
+
                         if (status == GDM_DISPLAY_FINISHED || g_strcmp0 (session_type, "x11") == 0) {
                                 manager->priv->ran_once = TRUE;
                         }
                         maybe_start_pending_initial_login (manager, display);
                         break;
                 default:
                         break;
         }
 
 }
 
 static void
 on_display_removed (GdmDisplayStore *display_store,
                     const char      *id,
                     GdmManager      *manager)
 {
         GdmDisplay *display;
 
         display = gdm_display_store_lookup (display_store, id);
         if (display != NULL) {
                 g_dbus_object_manager_server_unexport (manager->priv->object_manager, id);
 
                 g_signal_handlers_disconnect_by_func (display, G_CALLBACK (on_display_status_changed), manager);
 
                 g_signal_emit (manager, signals[DISPLAY_REMOVED], 0, id);
         }
 }
 
 static void
 destroy_start_user_session_operation (StartUserSessionOperation *operation)
@@ -2331,61 +2334,61 @@ on_session_reauthentication_started (GdmSession *session,
                                      int         pid_of_caller,
                                      const char *address,
                                      GdmManager *manager)
 {
         GDBusMethodInvocation *invocation;
         gpointer               source_tag;
 
         g_debug ("GdmManager: reauthentication started");
 
         source_tag = GINT_TO_POINTER (pid_of_caller);
 
         invocation = g_hash_table_lookup (manager->priv->open_reauthentication_requests,
                                           source_tag);
 
         if (invocation != NULL) {
                 g_hash_table_steal (manager->priv->open_reauthentication_requests,
                                     source_tag);
                 gdm_dbus_manager_complete_open_reauthentication_channel (GDM_DBUS_MANAGER (manager),
                                                                          invocation,
                                                                          address);
         }
 }
 
 static void
 clean_user_session (GdmSession *session)
 {
         g_object_set_data (G_OBJECT (session), "gdm-display", NULL);
         g_object_unref (session);
 }
 
-static GdmSession *
+static void
 create_user_session_for_display (GdmManager *manager,
                                  GdmDisplay *display,
                                  uid_t       allowed_user)
 {
         GdmSession *session;
         gboolean    display_is_local = FALSE;
         char       *display_name = NULL;
         char       *display_device = NULL;
         char       *remote_hostname = NULL;
         char       *display_auth_file = NULL;
         char       *display_seat_id = NULL;
         char       *display_id = NULL;
 #if defined(ENABLE_WAYLAND_SUPPORT) && defined(ENABLE_USER_DISPLAY_SERVER)
         char       *display_session_type = NULL;
         gboolean    greeter_is_wayland;
 #endif
 
         g_object_get (G_OBJECT (display),
                       "id", &display_id,
                       "x11-display-name", &display_name,
                       "is-local", &display_is_local,
                       "remote-hostname", &remote_hostname,
                       "x11-authority-file", &display_auth_file,
                       "seat-id", &display_seat_id,
 #if defined(ENABLE_WAYLAND_SUPPORT) && defined(ENABLE_USER_DISPLAY_SERVER)
                       "session-type", &display_session_type,
 #endif
                       NULL);
         display_device = get_display_device (manager, display);
 
@@ -2441,70 +2444,68 @@ create_user_session_for_display (GdmManager *manager,
                           "conversation-stopped",
                           G_CALLBACK (on_session_conversation_stopped),
                           manager);
         g_signal_connect (session,
                           "authentication-failed",
                           G_CALLBACK (on_session_authentication_failed),
                           manager);
         g_signal_connect (session,
                           "session-opened",
                           G_CALLBACK (on_user_session_opened),
                           manager);
         g_signal_connect (session,
                           "session-started",
                           G_CALLBACK (on_user_session_started),
                           manager);
         g_signal_connect (session,
                           "session-start-failed",
                           G_CALLBACK (on_session_start_failed),
                           manager);
         g_signal_connect (session,
                           "session-exited",
                           G_CALLBACK (on_user_session_exited),
                           manager);
         g_signal_connect (session,
                           "session-died",
                           G_CALLBACK (on_user_session_died),
                           manager);
         g_object_set_data (G_OBJECT (session), "gdm-display", display);
         g_object_set_data_full (G_OBJECT (display),
                                 "gdm-user-session",
-                                g_object_ref (session),
+                                session,
                                 (GDestroyNotify)
                                 clean_user_session);
 
 #if defined(ENABLE_WAYLAND_SUPPORT) && defined(ENABLE_USER_DISPLAY_SERVER)
         greeter_is_wayland = g_strcmp0 (display_session_type, "wayland") == 0;
         g_object_set (G_OBJECT (session), "ignore-wayland", !greeter_is_wayland, NULL);
 #endif
-
-        return session;
 }
 
 static void
 on_display_added (GdmDisplayStore *display_store,
                   const char      *id,
                   GdmManager      *manager)
 {
         GdmDisplay *display;
 
         display = gdm_display_store_lookup (display_store, id);
 
         if (display != NULL) {
                 g_dbus_object_manager_server_export (manager->priv->object_manager,
                                                      gdm_display_get_object_skeleton (display));
 
                 g_signal_connect (display, "notify::status",
                                   G_CALLBACK (on_display_status_changed),
                                   manager);
                 g_signal_emit (manager, signals[DISPLAY_ADDED], 0, id);
         }
 }
 
 GQuark
 gdm_manager_error_quark (void)
 {
         static GQuark ret = 0;
         if (ret == 0) {
                 ret = g_quark_from_static_string ("gdm_manager_error");
         }
 
-- 
2.26.2