Blame SOURCES/0015-libgdm-Don-t-leak-user-verifier-extensions-on-unlock.patch

b61949
From 760810cd751c8a511b4eb58c0159fef1163f7355 Mon Sep 17 00:00:00 2001
b61949
From: Ray Strode <rstrode@redhat.com>
b61949
Date: Fri, 25 Sep 2020 15:27:47 -0400
b61949
Subject: [PATCH 15/15] libgdm: Don't leak user verifier extensions on unlock
b61949
b61949
GdmClient fails to free the hash table associated with user
b61949
verifier extensions when the client is done with the user verifier.
b61949
b61949
This commit ties the user verifier extensions to the user verifier
b61949
instance associated with it, instead of storing the extensions
b61949
directly in the client struct.
b61949
---
b61949
 libgdm/gdm-client.c | 70 +++++++++++++++++++++++++++++++--------------
b61949
 1 file changed, 48 insertions(+), 22 deletions(-)
b61949
b61949
diff --git a/libgdm/gdm-client.c b/libgdm/gdm-client.c
b61949
index afe78087f..752961227 100644
b61949
--- a/libgdm/gdm-client.c
b61949
+++ b/libgdm/gdm-client.c
b61949
@@ -147,193 +147,204 @@ user_verifier_data_new (GTask *task, GdmUserVerifier *user_verifier)
b61949
 
b61949
         data = g_slice_new (UserVerifierData);
b61949
         data->task = g_object_ref (task);
b61949
         data->user_verifier = g_object_ref (user_verifier);
b61949
 
b61949
         return data;
b61949
 }
b61949
 
b61949
 static void
b61949
 user_verifier_data_free (UserVerifierData *data)
b61949
 {
b61949
         g_object_unref (data->task);
b61949
         g_object_unref (data->user_verifier);
b61949
         g_slice_free (UserVerifierData, data);
b61949
 }
b61949
 
b61949
 static void
b61949
 complete_user_verifier_proxy_operation (GdmClient          *client,
b61949
                                         UserVerifierData   *data)
b61949
 {
b61949
         g_task_return_pointer (data->task,
b61949
                                g_object_ref (data->user_verifier),
b61949
                                (GDestroyNotify) g_object_unref);
b61949
         user_verifier_data_free (data);
b61949
 }
b61949
 
b61949
 static void
b61949
 maybe_complete_user_verifier_proxy_operation (GdmClient          *client,
b61949
                                               UserVerifierData   *data)
b61949
 {
b61949
+        GHashTable *user_verifier_extensions;
b61949
         GHashTableIter iter;
b61949
         gpointer key, value;
b61949
 
b61949
-        if (client->priv->user_verifier_extensions != NULL) {
b61949
-                g_hash_table_iter_init (&iter, client->priv->user_verifier_extensions);
b61949
+        user_verifier_extensions = g_object_get_data (G_OBJECT (client->priv->user_verifier), "gdm-client-user-verifier-extensions");
b61949
+        if (user_verifier_extensions != NULL) {
b61949
+                g_hash_table_iter_init (&iter, user_verifier_extensions);
b61949
                 while (g_hash_table_iter_next (&iter, &key, &value)) {
b61949
                         if (value == NULL)
b61949
                                 return;
b61949
                 }
b61949
         }
b61949
 
b61949
         complete_user_verifier_proxy_operation (client, data);
b61949
 }
b61949
 
b61949
 static void
b61949
 on_user_verifier_choice_list_proxy_created (GObject            *source,
b61949
                                             GAsyncResult       *result,
b61949
                                             UserVerifierData   *data)
b61949
 {
b61949
+        GHashTable *user_verifier_extensions;
b61949
         g_autoptr(GdmClient)       client = NULL;
b61949
         GdmUserVerifierChoiceList *choice_list;
b61949
         g_autoptr(GError)          error = NULL;
b61949
 
b61949
         client = GDM_CLIENT (g_async_result_get_source_object (G_ASYNC_RESULT (data->task)));
b61949
 
b61949
+        user_verifier_extensions = g_object_get_data (G_OBJECT (data->user_verifier), "gdm-client-user-verifier-extensions");
b61949
         choice_list = gdm_user_verifier_choice_list_proxy_new_finish (result, &error);
b61949
 
b61949
         if (choice_list == NULL) {
b61949
                 g_debug ("Couldn't create UserVerifier ChoiceList proxy: %s", error->message);
b61949
-                g_hash_table_remove (client->priv->user_verifier_extensions, gdm_user_verifier_choice_list_interface_info ()->name);
b61949
+                g_hash_table_remove (user_verifier_extensions, gdm_user_verifier_choice_list_interface_info ()->name);
b61949
         } else {
b61949
-                g_hash_table_replace (client->priv->user_verifier_extensions, gdm_user_verifier_choice_list_interface_info ()->name, choice_list);
b61949
+                g_hash_table_replace (user_verifier_extensions, gdm_user_verifier_choice_list_interface_info ()->name, choice_list);
b61949
         }
b61949
 
b61949
         maybe_complete_user_verifier_proxy_operation (client, data);
b61949
 }
b61949
 
b61949
 static void
b61949
 on_user_verifier_extensions_enabled (GdmUserVerifier    *user_verifier,
b61949
                                      GAsyncResult       *result,
b61949
                                      UserVerifierData   *data)
b61949
 {
b61949
         g_autoptr(GdmClient)       client = NULL;
b61949
+        GHashTable *user_verifier_extensions;
b61949
         GCancellable *cancellable;
b61949
         GDBusConnection *connection;
b61949
         g_autoptr(GError) error = NULL;
b61949
         size_t     i;
b61949
 
b61949
         client = GDM_CLIENT (g_async_result_get_source_object (G_ASYNC_RESULT (data->task)));
b61949
         cancellable = g_task_get_cancellable (data->task);
b61949
+        user_verifier_extensions = g_object_get_data (G_OBJECT (user_verifier), "gdm-client-user-verifier-extensions");
b61949
 
b61949
         gdm_user_verifier_call_enable_extensions_finish (user_verifier, result, &error);
b61949
 
b61949
         if (error != NULL) {
b61949
                 g_debug ("Couldn't enable user verifier extensions: %s",
b61949
                          error->message);
b61949
                 complete_user_verifier_proxy_operation (client, data);
b61949
                 return;
b61949
         }
b61949
 
b61949
         connection = g_dbus_proxy_get_connection (G_DBUS_PROXY (user_verifier));
b61949
 
b61949
         for (i = 0; client->priv->enabled_extensions[i] != NULL; i++) {
b61949
                 g_debug ("Enabled extensions[%lu] = %s", i, client->priv->enabled_extensions[i]);
b61949
-                g_hash_table_insert (client->priv->user_verifier_extensions, client->priv->enabled_extensions[i], NULL);
b61949
+                g_hash_table_insert (user_verifier_extensions, client->priv->enabled_extensions[i], NULL);
b61949
 
b61949
                 if (strcmp (client->priv->enabled_extensions[i],
b61949
                             gdm_user_verifier_choice_list_interface_info ()->name) == 0) {
b61949
-                        g_hash_table_insert (client->priv->user_verifier_extensions, client->priv->enabled_extensions[i], NULL);
b61949
+                        g_hash_table_insert (user_verifier_extensions, client->priv->enabled_extensions[i], NULL);
b61949
                         gdm_user_verifier_choice_list_proxy_new (connection,
b61949
                                                                  G_DBUS_PROXY_FLAGS_NONE,
b61949
                                                                  NULL,
b61949
                                                                  SESSION_DBUS_PATH,
b61949
                                                                  cancellable,
b61949
                                                                  (GAsyncReadyCallback)
b61949
                                                                  on_user_verifier_choice_list_proxy_created,
b61949
                                                                  data);
b61949
                 } else {
b61949
                         g_debug ("User verifier extension %s is unsupported", client->priv->enabled_extensions[i]);
b61949
-                        g_hash_table_remove (client->priv->user_verifier_extensions,
b61949
+                        g_hash_table_remove (user_verifier_extensions,
b61949
                                              client->priv->enabled_extensions[i]);
b61949
                 }
b61949
         }
b61949
 
b61949
-        if (g_hash_table_size (client->priv->user_verifier_extensions) == 0) {
b61949
+        if (g_hash_table_size (user_verifier_extensions) == 0) {
b61949
                 g_debug ("No supported user verifier extensions");
b61949
                 complete_user_verifier_proxy_operation (client, data);
b61949
         }
b61949
 
b61949
 }
b61949
 
b61949
 static void
b61949
 free_interface_skeleton (GDBusInterfaceSkeleton *interface)
b61949
 {
b61949
         if (interface == NULL)
b61949
                 return;
b61949
 
b61949
         g_object_unref (interface);
b61949
 }
b61949
 
b61949
 static void
b61949
 on_user_verifier_proxy_created (GObject            *source,
b61949
                                 GAsyncResult       *result,
b61949
                                 gpointer            user_data)
b61949
 {
b61949
         g_autoptr(GdmClient)       self = NULL;
b61949
+        GHashTable         *user_verifier_extensions;
b61949
         GCancellable    *cancellable = NULL;
b61949
         g_autoptr(GdmUserVerifier) user_verifier = NULL;
b61949
         g_autoptr(GTask)           task = user_data;
b61949
         g_autoptr(GError)          error = NULL;
b61949
 
b61949
         user_verifier = gdm_user_verifier_proxy_new_finish (result, &error);
b61949
         if (user_verifier == NULL) {
b61949
                 g_task_return_error (task, g_steal_pointer (&error));
b61949
                 return;
b61949
         }
b61949
 
b61949
         g_debug ("UserVerifier %p created", user_verifier);
b61949
 
b61949
         self = GDM_CLIENT (g_async_result_get_source_object (G_ASYNC_RESULT (task)));
b61949
         if (self->priv->enabled_extensions == NULL) {
b61949
                 g_debug ("no enabled extensions");
b61949
                 g_task_return_pointer (task,
b61949
                                        g_steal_pointer (&user_verifier),
b61949
                                        (GDestroyNotify) g_object_unref);
b61949
                 return;
b61949
         }
b61949
 
b61949
-        self->priv->user_verifier_extensions = g_hash_table_new_full (g_str_hash,
b61949
-                                                                      g_str_equal,
b61949
-                                                                      NULL,
b61949
-                                                                      (GDestroyNotify)
b61949
-                                                                      free_interface_skeleton);
b61949
+        user_verifier_extensions = g_hash_table_new_full (g_str_hash,
b61949
+                                                          g_str_equal,
b61949
+                                                          NULL,
b61949
+                                                          (GDestroyNotify)
b61949
+                                                          free_interface_skeleton);
b61949
+        g_object_set_data_full (G_OBJECT (user_verifier),
b61949
+                                "gdm-client-user-verifier-extensions",
b61949
+                                user_verifier_extensions,
b61949
+                                (GDestroyNotify) g_hash_table_unref);
b61949
         cancellable = g_task_get_cancellable (task);
b61949
         gdm_user_verifier_call_enable_extensions (user_verifier,
b61949
                                                   (const char * const *)
b61949
                                                   self->priv->enabled_extensions,
b61949
                                                   cancellable,
b61949
                                                   (GAsyncReadyCallback)
b61949
                                                   on_user_verifier_extensions_enabled,
b61949
                                                   user_verifier_data_new (task, user_verifier));
b61949
 }
b61949
 
b61949
 static void
b61949
 on_reauthentication_channel_connected (GObject            *source_object,
b61949
                                        GAsyncResult       *result,
b61949
                                        gpointer            user_data)
b61949
 {
b61949
         GCancellable *cancellable;
b61949
         g_autoptr(GTask)           task = user_data;
b61949
         g_autoptr(GDBusConnection) connection = NULL;
b61949
         g_autoptr(GError)          error = NULL;
b61949
 
b61949
         connection = g_dbus_connection_new_for_address_finish (result, &error);
b61949
         if (!connection) {
b61949
                 g_task_return_error (task, g_steal_pointer (&error));
b61949
                 return;
b61949
         }
b61949
 
b61949
         cancellable = g_task_get_cancellable (task);
b61949
         gdm_user_verifier_proxy_new (connection,
b61949
                                      G_DBUS_PROXY_FLAGS_NONE,
b61949
                                      NULL,
b61949
@@ -637,87 +648,93 @@ gdm_client_open_reauthentication_channel_finish (GdmClient       *client,
b61949
  */
b61949
 GdmUserVerifier *
b61949
 gdm_client_get_user_verifier_sync (GdmClient     *client,
b61949
                                    GCancellable  *cancellable,
b61949
                                    GError       **error)
b61949
 {
b61949
         g_autoptr(GDBusConnection) connection = NULL;
b61949
 
b61949
         if (client->priv->user_verifier != NULL) {
b61949
                 return g_object_ref (client->priv->user_verifier);
b61949
         }
b61949
 
b61949
         connection = gdm_client_get_connection_sync (client, cancellable, error);
b61949
 
b61949
         if (connection == NULL) {
b61949
                 return NULL;
b61949
         }
b61949
 
b61949
         client->priv->user_verifier = gdm_user_verifier_proxy_new_sync (connection,
b61949
                                                                         G_DBUS_PROXY_FLAGS_NONE,
b61949
                                                                         NULL,
b61949
                                                                         SESSION_DBUS_PATH,
b61949
                                                                         cancellable,
b61949
                                                                         error);
b61949
 
b61949
         if (client->priv->user_verifier != NULL) {
b61949
                 g_object_add_weak_pointer (G_OBJECT (client->priv->user_verifier),
b61949
                                            (gpointer *)
b61949
                                            &client->priv->user_verifier);
b61949
                 if (client->priv->enabled_extensions != NULL) {
b61949
+                        GHashTable *user_verifier_extensions;
b61949
                         gboolean res;
b61949
 
b61949
-                        client->priv->user_verifier_extensions = g_hash_table_new_full (g_str_hash,
b61949
-                                                                                        g_str_equal,
b61949
-                                                                                        NULL,
b61949
-                                                                                        (GDestroyNotify)
b61949
-                                                                                        free_interface_skeleton);
b61949
+                        user_verifier_extensions = g_hash_table_new_full (g_str_hash,
b61949
+                                                                          g_str_equal,
b61949
+                                                                          NULL,
b61949
+                                                                          (GDestroyNotify)
b61949
+                                                                          free_interface_skeleton);
b61949
+                        g_object_set_data_full (G_OBJECT (client->priv->user_verifier),
b61949
+                                                "gdm-client-user-verifier-extensions",
b61949
+                                                user_verifier_extensions,
b61949
+                                                (GDestroyNotify) g_hash_table_unref);
b61949
+
b61949
                         res = gdm_user_verifier_call_enable_extensions_sync (client->priv->user_verifier,
b61949
                                                                             (const char * const *)
b61949
                                                                              client->priv->enabled_extensions,
b61949
                                                                              cancellable,
b61949
                                                                              NULL);
b61949
 
b61949
                         if (res) {
b61949
                                 size_t i;
b61949
                                 for (i = 0; client->priv->enabled_extensions[i] != NULL; i++) {
b61949
                                             if (strcmp (client->priv->enabled_extensions[i],
b61949
                                                         gdm_user_verifier_choice_list_interface_info ()->name) == 0) {
b61949
                                                         GdmUserVerifierChoiceList *choice_list_interface;
b61949
                                                         choice_list_interface = gdm_user_verifier_choice_list_proxy_new_sync (connection,
b61949
                                                                                                                               G_DBUS_PROXY_FLAGS_NONE,
b61949
                                                                                                                               NULL,
b61949
                                                                                                                               SESSION_DBUS_PATH,
b61949
                                                                                                                               cancellable,
b61949
                                                                                                                               NULL);
b61949
                                                         if (choice_list_interface != NULL)
b61949
-                                                                    g_hash_table_insert (client->priv->user_verifier_extensions, client->priv->enabled_extensions[i], choice_list_interface);
b61949
+                                                                    g_hash_table_insert (user_verifier_extensions, client->priv->enabled_extensions[i], choice_list_interface);
b61949
                                             }
b61949
                                 }
b61949
                         }
b61949
                 }
b61949
         }
b61949
 
b61949
         return client->priv->user_verifier;
b61949
 }
b61949
 
b61949
 static void
b61949
 on_connection_for_user_verifier (GdmClient          *client,
b61949
                                  GAsyncResult       *result,
b61949
                                  gpointer            user_data)
b61949
 {
b61949
         GCancellable *cancellable;
b61949
         g_autoptr(GTask)           task = user_data;
b61949
         g_autoptr(GDBusConnection) connection = NULL;
b61949
         g_autoptr(GError)          error = NULL;
b61949
 
b61949
         connection = gdm_client_get_connection_finish (client, result, &error);
b61949
         if (connection == NULL) {
b61949
                 g_task_return_error (task, g_steal_pointer (&error));
b61949
                 return;
b61949
         }
b61949
 
b61949
         cancellable = g_task_get_cancellable (task);
b61949
         gdm_user_verifier_proxy_new (connection,
b61949
                                      G_DBUS_PROXY_FLAGS_NONE,
b61949
                                      NULL,
b61949
                                      SESSION_DBUS_PATH,
b61949
@@ -765,86 +782,95 @@ gdm_client_get_user_verifier (GdmClient           *client,
b61949
                                    g_steal_pointer (&task));
b61949
 }
b61949
 
b61949
 /**
b61949
  * gdm_client_get_user_verifier_finish:
b61949
  * @client: a #GdmClient
b61949
  * @result: The #GAsyncResult from the callback
b61949
  * @error: a #GError
b61949
  *
b61949
  * Finishes an operation started with
b61949
  * gdm_client_get_user_verifier().
b61949
  *
b61949
  * Returns: (transfer full): a #GdmUserVerifier
b61949
  */
b61949
 GdmUserVerifier *
b61949
 gdm_client_get_user_verifier_finish (GdmClient       *client,
b61949
                                      GAsyncResult    *result,
b61949
                                      GError         **error)
b61949
 {
b61949
         GdmUserVerifier *user_verifier;
b61949
 
b61949
         g_return_val_if_fail (GDM_IS_CLIENT (client), NULL);
b61949
 
b61949
         if (client->priv->user_verifier != NULL)
b61949
                 return g_object_ref (client->priv->user_verifier);
b61949
 
b61949
         user_verifier = g_task_propagate_pointer (G_TASK (result), error);
b61949
         if (user_verifier == NULL)
b61949
                 return NULL;
b61949
 
b61949
-        client->priv->user_verifier = user_verifier;
b61949
+        if (client->priv->user_verifier != NULL) {
b61949
+                g_object_remove_weak_pointer (G_OBJECT (client->priv->user_verifier),
b61949
+                                              (gpointer *)
b61949
+                                              &client->priv->user_verifier);
b61949
+        }
b61949
 
b61949
         g_object_add_weak_pointer (G_OBJECT (client->priv->user_verifier),
b61949
                                    (gpointer *)
b61949
                                    &client->priv->user_verifier);
b61949
 
b61949
+        client->priv->user_verifier = user_verifier;
b61949
+
b61949
         return user_verifier;
b61949
 }
b61949
 
b61949
 /**
b61949
  * gdm_client_get_user_verifier_choice_list:
b61949
  * @client: a #GdmClient
b61949
  *
b61949
  * Gets a #GdmUserVerifierChoiceList object that can be used to
b61949
  * verify a user's local account.
b61949
  *
b61949
  * Returns: (transfer none): #GdmUserVerifierChoiceList or %NULL if user
b61949
  * verifier isn't yet fetched, or daemon doesn't support choice lists
b61949
  */
b61949
 GdmUserVerifierChoiceList *
b61949
 gdm_client_get_user_verifier_choice_list (GdmClient *client)
b61949
 {
b61949
-        if (client->priv->user_verifier_extensions == NULL)
b61949
+        GHashTable *user_verifier_extensions;
b61949
+
b61949
+        user_verifier_extensions = g_object_get_data (G_OBJECT (client->priv->user_verifier), "gdm-client-user-verifier-extensions");
b61949
+        if (user_verifier_extensions == NULL)
b61949
                 return NULL;
b61949
 
b61949
-        return g_hash_table_lookup (client->priv->user_verifier_extensions,
b61949
+        return g_hash_table_lookup (user_verifier_extensions,
b61949
                                     gdm_user_verifier_choice_list_interface_info ()->name);
b61949
 }
b61949
 
b61949
 static void
b61949
 on_timed_login_details_got (GdmGreeter   *greeter,
b61949
                             GAsyncResult *result)
b61949
 {
b61949
     gdm_greeter_call_get_timed_login_details_finish (greeter, NULL, NULL, NULL, result, NULL);
b61949
 }
b61949
 
b61949
 static void
b61949
 query_for_timed_login_requested_signal (GdmGreeter *greeter)
b61949
 {
b61949
         /* This just makes sure a timed-login-requested signal gets fired
b61949
          * off if appropriate.
b61949
          */
b61949
         gdm_greeter_call_get_timed_login_details (greeter,
b61949
                                                   NULL,
b61949
                                                   (GAsyncReadyCallback)
b61949
                                                   on_timed_login_details_got,
b61949
                                                   NULL);
b61949
 }
b61949
 
b61949
 static void
b61949
 on_greeter_proxy_created (GObject            *source,
b61949
                           GAsyncResult       *result,
b61949
                           gpointer            user_data)
b61949
 {
b61949
         g_autoptr(GTask)  task = user_data;
b61949
         g_autoptr(GError) error = NULL;
b61949
-- 
b61949
2.26.2
b61949