From 7d4eed356eb8a9a87f49d49405ab506271178968 Mon Sep 17 00:00:00 2001 From: Ray Strode 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