diff --git a/SOURCES/0001-manager-Don-t-leak-session-objects.patch b/SOURCES/0001-manager-Don-t-leak-session-objects.patch new file mode 100644 index 0000000..909ca20 --- /dev/null +++ b/SOURCES/0001-manager-Don-t-leak-session-objects.patch @@ -0,0 +1,353 @@ +From de229615d80fd7c8a38ab5d5d7b30aa98f43721d 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 bff602a07..738671679 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 did_automatic_login : 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; + } +@@ -1343,61 +1343,62 @@ get_automatic_login_details (GdmManager *manager, + return enabled; + } + + 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; + + /* 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), + "session-type", &display_session_type, + NULL); + + g_object_set (G_OBJECT (session), + "display-is-initial", FALSE, + 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; + } + +@@ -1549,60 +1550,62 @@ on_display_status_changed (GdmDisplay *display, + "session-type", &session_type, + NULL); + + status = gdm_display_get_status (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); + } + 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 (display == manager->priv->automatic_login_display) { + g_clear_weak_pointer (&manager->priv->automatic_login_display); + + manager->priv->did_automatic_login = TRUE; + + #ifdef ENABLE_WAYLAND_SUPPORT + if (g_strcmp0 (session_type, "wayland") != 0 && status == GDM_DISPLAY_FAILED) { + /* we're going to fall back to X11, so try to autologin again + */ + manager->priv->did_automatic_login = FALSE; + } + #endif + } + break; + default: + break; + } + + } + + static void + on_display_removed (GdmDisplayStore *display_store, + GdmDisplay *display, + GdmManager *manager) + { + char *id; + + gdm_display_get_id (display, &id, NULL); + g_dbus_object_manager_server_unexport (manager->priv->object_manager, id); + g_free (id); +@@ -2292,61 +2295,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); + +@@ -2402,70 +2405,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 + diff --git a/SOURCES/0002-session-Don-t-leak-remote-greeter-interface.patch b/SOURCES/0002-session-Don-t-leak-remote-greeter-interface.patch new file mode 100644 index 0000000..b3e80dd --- /dev/null +++ b/SOURCES/0002-session-Don-t-leak-remote-greeter-interface.patch @@ -0,0 +1,87 @@ +From aeb88313c2110389ec530c8c7d5d816bac24d254 Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Tue, 15 Sep 2020 00:41:00 -0400 +Subject: [PATCH 2/3] session: Don't leak remote greeter interface + +XDMCP login screens get a "Remote Geeter Interface" exported over +the bus connection (so the login window can provide a Disconnect +button). + +This interface is getting leaked when the session object is disposed, +leaving the bus connection itself undisposed, which causes an fd +leak. + +This commit plugs the interface leak, and thus the fd leak. +--- + daemon/gdm-session.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/daemon/gdm-session.c b/daemon/gdm-session.c +index 540a2534d..d6d8f128a 100644 +--- a/daemon/gdm-session.c ++++ b/daemon/gdm-session.c +@@ -3602,60 +3602,61 @@ gdm_session_get_property (GObject *object, + break; + #ifdef ENABLE_WAYLAND_SUPPORT + case PROP_IGNORE_WAYLAND: + g_value_set_boolean (value, self->priv->ignore_wayland); + break; + #endif + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } + } + + static void + gdm_session_dispose (GObject *object) + { + GdmSession *self; + + self = GDM_SESSION (object); + + g_debug ("GdmSession: Disposing session"); + + gdm_session_close (self); + + g_clear_pointer (&self->priv->conversations, + g_hash_table_unref); + + g_clear_object (&self->priv->user_verifier_interface); + g_clear_pointer (&self->priv->user_verifier_extensions, + g_hash_table_unref); + g_clear_object (&self->priv->greeter_interface); ++ g_clear_object (&self->priv->remote_greeter_interface); + g_clear_object (&self->priv->chooser_interface); + + g_free (self->priv->display_name); + self->priv->display_name = NULL; + + g_free (self->priv->display_hostname); + self->priv->display_hostname = NULL; + + g_free (self->priv->display_device); + self->priv->display_device = NULL; + + g_free (self->priv->display_seat_id); + self->priv->display_seat_id = NULL; + + g_free (self->priv->display_x11_authority_file); + self->priv->display_x11_authority_file = NULL; + + g_strfreev (self->priv->conversation_environment); + self->priv->conversation_environment = NULL; + + if (self->priv->worker_server != NULL) { + g_dbus_server_stop (self->priv->worker_server); + g_clear_object (&self->priv->worker_server); + } + + if (self->priv->outside_server != NULL) { + g_dbus_server_stop (self->priv->outside_server); + g_clear_object (&self->priv->outside_server); + } + +-- +2.26.2 + diff --git a/SOURCES/0003-xdmcp-display-factory-Clear-launch-environment-when-.patch b/SOURCES/0003-xdmcp-display-factory-Clear-launch-environment-when-.patch new file mode 100644 index 0000000..2ff5c46 --- /dev/null +++ b/SOURCES/0003-xdmcp-display-factory-Clear-launch-environment-when-.patch @@ -0,0 +1,87 @@ +From 7c9e236f9015aae2ea5868b67ff8036766cb7099 Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Tue, 15 Sep 2020 11:28:48 -0400 +Subject: [PATCH 3/3] xdmcp-display-factory: Clear launch environment when done + with it + +The XDMCP disply factory examines the sessions of its displays' +launch environments when the displays change status. + +Unfortunately it leaks a reference to the launch environment when +doing that. + +This commit fixes the reference leak which leads to an fd leak. +--- + daemon/gdm-xdmcp-display-factory.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/daemon/gdm-xdmcp-display-factory.c b/daemon/gdm-xdmcp-display-factory.c +index 2e14beab4..98232113f 100644 +--- a/daemon/gdm-xdmcp-display-factory.c ++++ b/daemon/gdm-xdmcp-display-factory.c +@@ -2091,60 +2091,62 @@ on_display_status_changed (GdmDisplay *display, + gdm_display_factory_queue_purge_displays (GDM_DISPLAY_FACTORY (factory)); + break; + case GDM_DISPLAY_FAILED: + gdm_display_factory_queue_purge_displays (GDM_DISPLAY_FACTORY (factory)); + break; + case GDM_DISPLAY_UNMANAGED: + if (session != NULL) { + g_signal_handlers_disconnect_by_func (G_OBJECT (session), + G_CALLBACK (on_client_disconnected), + display); + } + break; + case GDM_DISPLAY_PREPARED: + break; + case GDM_DISPLAY_MANAGED: + if (session != NULL) { + g_signal_connect_object (G_OBJECT (session), + "client-disconnected", + G_CALLBACK (on_client_disconnected), + display, G_CONNECT_SWAPPED); + g_signal_connect_object (G_OBJECT (session), + "disconnected", + G_CALLBACK (on_client_disconnected), + display, G_CONNECT_SWAPPED); + } + break; + default: + g_assert_not_reached (); + break; + } ++ ++ g_clear_object (&launch_environment); + } + + static GdmDisplay * + gdm_xdmcp_display_create (GdmXdmcpDisplayFactory *factory, + const char *hostname, + GdmAddress *address, + int displaynum) + { + GdmDisplay *display; + GdmDisplayStore *store; + gboolean use_chooser; + + g_debug ("GdmXdmcpDisplayFactory: Creating xdmcp display for %s:%d", + hostname ? hostname : "(null)", displaynum); + + use_chooser = FALSE; + if (factory->priv->honor_indirect) { + IndirectClient *ic; + + ic = indirect_client_lookup (factory, address); + + /* This was an indirect thingie and nothing was yet chosen, + * use a chooser */ + if (ic != NULL && ic->chosen_address == NULL) { + use_chooser = TRUE; + } + } + + if (use_chooser) { + display = gdm_xdmcp_chooser_display_new (hostname, +-- +2.26.2 + diff --git a/SPECS/gdm.spec b/SPECS/gdm.spec index e716a26..ca1c090 100644 --- a/SPECS/gdm.spec +++ b/SPECS/gdm.spec @@ -10,7 +10,7 @@ Name: gdm Epoch: 1 Version: 3.28.3 -Release: 33%{?dist} +Release: 34%{?dist} Summary: The GNOME Display Manager License: GPLv2+ @@ -110,6 +110,10 @@ Patch200049: 0049-GdmManager-GdmDisplay-Add-RegisterSession-method.patch Patch200050: 0050-Allow-sessions-to-register-with-GDM.patch Patch200051: 0051-display-Handle-failure-before-display-registration.patch +Patch300001: 0001-manager-Don-t-leak-session-objects.patch +Patch300002: 0002-session-Don-t-leak-remote-greeter-interface.patch +Patch300003: 0003-xdmcp-display-factory-Clear-launch-environment-when-.patch + Patch900001: 0001-data-add-system-dconf-databases-to-gdm-profile.patch BuildRequires: pam-devel >= 0:%{pam_version} @@ -415,6 +419,10 @@ fi %{_libdir}/pkgconfig/gdm-pam-extensions.pc %changelog +* Tue Sep 15 2020 Ray Strode - 3.28.3-34 +- Fix file descriptor leak + Resolves: #1877853 + * Tue Sep 01 2020 Ray Strode - 3.28.3-33 - Fix problem with Xorg fallback Resolves: #1868260