From 1598a4476466822e7e9c757ac471089d3db4b545 Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Wed, 20 Jul 2016 11:35:05 +0900 Subject: [PATCH] scd: Fix card removal/reset on multiple contexts. * 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. -- Signed-off-by: NIIBE Yutaka --- scd/app.c | 4 +++ scd/command.c | 86 ++++++++++++++++++++++++++------------------------- 2 files changed, 48 insertions(+), 42 deletions(-) diff --git a/scd/app.c b/scd/app.c index 51464a2d8..55b8edd12 100644 --- a/scd/app.c +++ b/scd/app.c @@ -168,8 +168,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); diff --git a/scd/command.c b/scd/command.c index 5842ee752..d90c32042 100644 --- a/scd/command.c +++ b/scd/command.c @@ -129,10 +129,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; @@ -209,14 +205,28 @@ update_card_removed (int vrdr, int value) return; for (sl=session_list; sl; sl = sl->next_session) - if (sl->ctrl_backlink - && sl->ctrl_backlink->server_local->vreader_idx == vrdr) - { - sl->card_removed = value; - } + { + ctrl_t ctrl = sl->ctrl_backlink; + + if (ctrl && ctrl->server_local->vreader_idx == vrdr) + { + 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 (vreader_slot (vrdr)); + { + log_debug ("Removal of a card: %d\n", vrdr); + application_notify_card_reset (vreader_slot (vrdr)); + vreader_table[vrdr].slot = -1; + } } @@ -266,23 +276,31 @@ do_reset (ctrl_t ctrl, int send_reset) if (!(vrdr == -1 || (vrdr >= 0 && vrdr < DIM(vreader_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) - { - struct server_local_s *sl; + } - for (sl=session_list; sl; sl = sl->next_session) - if (sl->ctrl_backlink - && sl->ctrl_backlink->server_local->vreader_idx == vrdr) - { - sl->app_ctx_marked_for_release = 1; - } + /* 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) + { + ctrl_t c = sl->ctrl_backlink; + + if (c && c != ctrl && c->server_local->vreader_idx == vrdr) + { + struct app_ctx_s *app0 = c->app_ctx; + if (app0) + { + c->app_ctx = NULL; + release_application (app0); + } + } } } @@ -300,8 +318,8 @@ do_reset (ctrl_t ctrl, int send_reset) case SW_HOST_CARD_INACTIVE: break; default: - apdu_close_reader (slot); - vreader_table[vrdr].slot = slot = -1; + apdu_close_reader (slot); + vreader_table[vrdr].slot = -1; break; } } @@ -427,16 +445,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. */ @@ -2031,14 +2039,10 @@ scd_command_handler (ctrl_t ctrl, int fd) session_list = ctrl->server_local; ctrl->server_local->ctrl_backlink = ctrl; ctrl->server_local->assuan_ctx = ctx; - ctrl->server_local->vreader_idx = -1; /* We open the reader right at startup so that the ticker is able to update the status file. */ - if (ctrl->server_local->vreader_idx == -1) - { - ctrl->server_local->vreader_idx = get_current_reader (); - } + ctrl->server_local->vreader_idx = get_current_reader (); /* Command processing loop. */ for (;;) @@ -2256,9 +2260,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 (vr->slot); - apdu_close_reader (vr->slot); - vr->slot = -1; + apdu_close_reader (vr->slot); status = 0; changed = vr->changed; }