From 7c9a04c2ae838960e0694a1f843a71da5dec1f95 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Wed, 16 Dec 2020 11:13:20 +0100 Subject: [PATCH] device: Fix race when client vanishes from bus We have a condition where a client vanishing instead of cleaning up the operation using VerifyStop would cause fprintd to hang. This only happens if the underlying enroll/verify/identify operation has already finished when the client vanishes. Fix this by correctly interpreting current_cancellable as a flag for these operations. Fixes: #97 --- src/device.c | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/src/device.c b/src/device.c index c9145a0..28b3635 100644 --- a/src/device.c +++ b/src/device.c @@ -794,15 +794,30 @@ _fprint_device_client_vanished (GDBusConnection *connection, if (session != NULL && g_strcmp0 (session->sender, name) == 0) { - while (priv->current_action != ACTION_NONE) - { - /* OPEN/CLOSE are not cancellable, we just need to wait */ - if (priv->current_cancellable) - g_cancellable_cancel (priv->current_cancellable); + g_cancellable_cancel (priv->current_cancellable); - g_main_context_iteration (NULL, TRUE); + if (!priv->current_cancellable) + { + /* This isn't optimal, but for verify/identify/enroll we expect the stop + * command. And we use current_cancellable as a flag to know that the + * underlying operation has finished already. + * If it has finished, unset the current_action. */ + switch (priv->current_action) + { + case ACTION_VERIFY: + case ACTION_IDENTIFY: + case ACTION_ENROLL: + priv->current_action = ACTION_NONE; + break; + + default: + break; + } } + while (priv->current_action != ACTION_NONE) + g_main_context_iteration (NULL, TRUE); + /* The session may have disappeared at this point if the device * was already closing. */ g_clear_pointer (&session, session_data_unref);