From b0fb67c05e19a1a8715c1045f02657055d9e2578 Mon Sep 17 00:00:00 2001 From: Marek Kasik Date: Wed, 22 May 2019 14:56:42 +0200 Subject: [PATCH 1/4] smartcard: Cancel cancellable when stopping self->cancellable in GsdSmartcardManager is not cancelled at gsd_smartcard_manager_stop() and hence some callbacks are still called after unload_nss() which clears SECMODListLock which is used by SECMOD_GetReadLock() / SECMOD_ReleaseReadLock(). This leads to crashes in NSSRWLock_LockRead_Util() and NSSRWLock_UnlockRead_Util() probably. Also check for return value of g_cancellable_connect() and initialize pointer to PK11SlotInfo. See https://bugzilla.redhat.com/show_bug.cgi?id=1646359, https://bugzilla.redhat.com/show_bug.cgi?id=1688791 and their duplicates for additional info. --- plugins/smartcard/gsd-smartcard-manager.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/plugins/smartcard/gsd-smartcard-manager.c b/plugins/smartcard/gsd-smartcard-manager.c index 94ffdd90..09ccecc0 100644 --- a/plugins/smartcard/gsd-smartcard-manager.c +++ b/plugins/smartcard/gsd-smartcard-manager.c @@ -157,71 +157,72 @@ unload_nss (GsdSmartcardManager *self) if (self->priv->nss_context != NULL) { g_clear_pointer (&self->priv->nss_context, NSS_ShutdownContext); g_debug ("NSS database '%s' unloaded", GSD_SMARTCARD_MANAGER_NSS_DB); } else { g_debug ("NSS database '%s' already not loaded", GSD_SMARTCARD_MANAGER_NSS_DB); } } typedef struct { SECMODModule *driver; GHashTable *smartcards; int number_of_consecutive_errors; } WatchSmartcardsOperation; static void on_watch_cancelled (GCancellable *cancellable, WatchSmartcardsOperation *operation) { SECMOD_CancelWait (operation->driver); } static gboolean watch_one_event_from_driver (GsdSmartcardManager *self, WatchSmartcardsOperation *operation, GCancellable *cancellable, GError **error) { GsdSmartcardManagerPrivate *priv = self->priv; - PK11SlotInfo *card, *old_card; + PK11SlotInfo *card = NULL, *old_card; CK_SLOT_ID slot_id; gulong handler_id; int old_slot_series = -1, slot_series; handler_id = g_cancellable_connect (cancellable, G_CALLBACK (on_watch_cancelled), operation, NULL); - card = SECMOD_WaitForAnyTokenEvent (operation->driver, 0, PR_SecondsToInterval (1)); + if (handler_id != 0) + card = SECMOD_WaitForAnyTokenEvent (operation->driver, 0, PR_SecondsToInterval (1)); g_cancellable_disconnect (cancellable, handler_id); if (g_cancellable_set_error_if_cancelled (cancellable, error)) { g_warning ("smartcard event function cancelled"); return FALSE; } if (card == NULL) { int error_code; error_code = PORT_GetError (); operation->number_of_consecutive_errors++; if (operation->number_of_consecutive_errors > 10) { g_warning ("Got %d consecutive smartcard errors, so giving up.", operation->number_of_consecutive_errors); g_set_error (error, GSD_SMARTCARD_MANAGER_ERROR, GSD_SMARTCARD_MANAGER_ERROR_WITH_NSS, "encountered unexpected error while " "waiting for smartcard events (error %x)", error_code); return FALSE; } g_warning ("Got potentially spurious smartcard event error: %x.", error_code); g_usleep (0.5 * G_USEC_PER_SEC); @@ -764,60 +765,62 @@ gsd_smartcard_manager_idle_cb (GsdSmartcardManager *self) gnome_settings_profile_end (NULL); priv->start_idle_id = 0; return FALSE; } gboolean gsd_smartcard_manager_start (GsdSmartcardManager *self, GError **error) { GsdSmartcardManagerPrivate *priv = self->priv; gnome_settings_profile_start (NULL); priv->start_idle_id = g_idle_add ((GSourceFunc) gsd_smartcard_manager_idle_cb, self); g_source_set_name_by_id (priv->start_idle_id, "[gnome-settings-daemon] gsd_smartcard_manager_idle_cb"); gnome_settings_profile_end (NULL); return TRUE; } void gsd_smartcard_manager_stop (GsdSmartcardManager *self) { GsdSmartcardManagerPrivate *priv = self->priv; g_debug ("Stopping smartcard manager"); + g_cancellable_cancel (priv->cancellable); + unload_nss (self); g_clear_object (&priv->settings); g_clear_object (&priv->cancellable); g_clear_object (&priv->session_manager); g_clear_object (&priv->screen_saver); } static void on_screen_locked (GsdScreenSaver *screen_saver, GAsyncResult *result, GsdSmartcardManager *self) { gboolean is_locked; GError *error = NULL; is_locked = gsd_screen_saver_call_lock_finish (screen_saver, result, &error); if (!is_locked) { g_warning ("Couldn't lock screen: %s", error->message); g_error_free (error); return; } } static void lock_screen (GsdSmartcardManager *self) { GsdSmartcardManagerPrivate *priv = self->priv; -- 2.39.2