scd: Fix card removal/reset on multiple contexts.
authorNIIBE Yutaka <gniibe@fsij.org>
Wed, 20 Jul 2016 02:35:05 +0000 (11:35 +0900)
committerNIIBE Yutaka <gniibe@fsij.org>
Tue, 29 Nov 2016 08:39:00 +0000 (17:39 +0900)
* scd/app.c (application_notify_card_reset): Add message for debug.
*scd/command.c (update_card_removed): Call release_application and set
SLOT -1 here.
(struct server_local_s): Remove app_ctx_marked_for_release.
(do_reset): Don't mark release but call release_application here.
(open_card): Remove app_ctx_marked_for_release handling.
(update_reader_status_file): Don't set SLOT here, so that it can be
released the APP by application_notify_card_reset in
update_card_removed.
--
Backport of master commit: 1598a4476466822e7e9c757ac471089d3db4b545

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
scd/app.c
scd/command.c

index 0f36409..24ed5b0 100644 (file)
--- a/scd/app.c
+++ b/scd/app.c
@@ -183,8 +183,12 @@ application_notify_card_reset (int slot)
   /* Release the APP, as it's not reusable any more.  */
   if (lock_table[slot].app)
     {
+      if (lock_table[slot].app->ref_count)
+        log_bug ("trying to release active context\n");
+
       deallocate_app (lock_table[slot].app);
       lock_table[slot].app = NULL;
+      log_debug ("application has been released\n");
     }
 
   unlock_reader (slot);
index 24c51c8..451a922 100644 (file)
@@ -118,10 +118,6 @@ struct server_local_s
      continue operation. */
   int card_removed;
 
-  /* Flag indicating that the application context needs to be released
-     at the next opportunity.  */
-  int app_ctx_marked_for_release;
-
   /* A disconnect command has been sent.  */
   int disconnect_allowed;
 
@@ -185,14 +181,28 @@ update_card_removed (int slot, int value)
     return;
 
   for (sl=session_list; sl; sl = sl->next_session)
-    if (sl->ctrl_backlink
-        && sl->ctrl_backlink->reader_slot == slot)
-      {
-        sl->card_removed = value;
-      }
+    {
+      ctrl_t ctrl = sl->ctrl_backlink;
+
+      if (ctrl && ctrl->reader_slot == slot)
+        {
+          sl->card_removed = value;
+          if (value)
+            {
+              struct app_ctx_s *app = ctrl->app_ctx;
+              ctrl->app_ctx = NULL;
+              release_application (app);
+            }
+        }
+    }
+
   /* Let the card application layer know about the removal.  */
   if (value)
-    application_notify_card_reset (slot);
+    {
+      log_debug ("Removal of a card: %d\n", slot);
+      application_notify_card_reset (slot);
+      slot_table[slot].slot = -1;
+    }
 }
 
 
@@ -288,23 +298,31 @@ do_reset (ctrl_t ctrl, int send_reset)
   if (!(slot == -1 || (slot >= 0 && slot < DIM(slot_table))))
     BUG ();
 
-  /* If there is an active application, release it.  Tell all other
-     sessions using the same application to release the
-     application.  */
+  /* If there is an active application, release it. */
   if (app)
     {
       ctrl->app_ctx = NULL;
       release_application (app);
-      if (send_reset)
+    }
+
+  /* Release the same application which is used by other sessions.  */
+  if (send_reset)
+    {
+      struct server_local_s *sl;
+
+      for (sl=session_list; sl; sl = sl->next_session)
         {
-          struct server_local_s *sl;
+          ctrl_t c = sl->ctrl_backlink;
 
-          for (sl=session_list; sl; sl = sl->next_session)
-            if (sl->ctrl_backlink
-                && sl->ctrl_backlink->reader_slot == slot)
-              {
-                sl->app_ctx_marked_for_release = 1;
-              }
+          if (c && c != ctrl && c->reader_slot == slot)
+            {
+              struct app_ctx_s *app0 = c->app_ctx;
+              if (app0)
+                {
+                  c->app_ctx = NULL;
+                  release_application (app0);
+                }
+            }
         }
     }
 
@@ -444,16 +462,6 @@ open_card (ctrl_t ctrl, const char *apptype)
   if ( IS_LOCKED (ctrl) )
     return gpg_error (GPG_ERR_LOCKED);
 
-  /* If the application has been marked for release do it now.  We
-     can't do it immediately in do_reset because the application may
-     still be in use.  */
-  if (ctrl->server_local->app_ctx_marked_for_release)
-    {
-      ctrl->server_local->app_ctx_marked_for_release = 0;
-      release_application (ctrl->app_ctx);
-      ctrl->app_ctx = NULL;
-    }
-
   /* If we are already initialized for one specific application we
      need to check that the client didn't requested a specific
      application different from the one in use before we continue. */
@@ -2009,10 +2017,7 @@ scd_command_handler (ctrl_t ctrl, int fd)
 
   /* We open the reader right at startup so that the ticker is able to
      update the status file. */
-  if (ctrl->reader_slot == -1)
-    {
-      ctrl->reader_slot = get_reader_slot ();
-    }
+  ctrl->reader_slot = get_reader_slot ();
 
   /* Command processing loop. */
   for (;;)
@@ -2230,9 +2235,7 @@ update_reader_status_file (int set_card_removed_flag)
       if (sw_apdu == SW_HOST_NO_READER)
         {
           /* Most likely the _reader_ has been unplugged.  */
-         application_notify_card_reset (ss->slot);
          apdu_close_reader (ss->slot);
-         ss->valid = 0;
           status = 0;
           changed = ss->changed;
         }