1
0
mirror of git://git.gnupg.org/gnupg.git synced 2024-12-22 10:19:57 +01:00

scd: Internal CCID driver: Fix a race condition on close.

* scd/ccid-driver.c (ccid_require_get_status): For VENDOR_SCM reader,
return 0 only at the initial call.
(bulk_in): Don't detect an error for VENDOR_SCM reader, just kicking
the loop, to invoke scd_update_reader_status_file, which calls
ccid_slot_status again.
(ccid_slot_status): Move the call of ccid_vendor_specific_setup to...
(ccid_get_atr): ... here.

--

For readers with interrupt transfer support, it is only intr_cb which
sets handle->powered_off to 1.  Keeping this condition makes no race.
The function ccid_slot_status can also detect a communication error,
which causes apdu_close_reader (but not setting ->powered_off).

GnuPG-bug-id: 5121
Fixes-commit: 920f258eb6018ecec1d63bad6a0fb0772f72affa
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
(cherry picked from commit 484bafda4dbf5ffe9e7c41ef24fbc5bd791a3b32)
This commit is contained in:
NIIBE Yutaka 2020-11-05 15:10:18 +09:00 committed by Werner Koch
parent 7f765a98fd
commit 8e206c1721
No known key found for this signature in database
GPG Key ID: E3FDFF218E45B72B

View File

@ -1799,8 +1799,26 @@ ccid_require_get_status (ccid_driver_t handle)
detect removal of a card and can detect removal of a reader.
*/
if (handle->ep_intr >= 0)
{
if (handle->id_vendor != VENDOR_SCM)
return 0;
/*
* For card reader with interrupt transfer support, ideally,
* removal is detected by intr_cb, but some card reader
* (e.g. SPR532) has a possible case of missing report to
* intr_cb, and another case of valid report to intr_cb.
*
* For such a reader, the removal should be able to be detected
* by PC_to_RDR_GetSlotStatus, too. Thus, calls to
* ccid_slot_status should go on wire even if "on_wire" is not
* requested.
*
*/
if (handle->transfer == NULL)
return 0;
}
/* Libusb actually detects the removal of USB device in use.
However, there is no good API to handle the removal (yet),
cleanly and with good portability.
@ -2160,20 +2178,17 @@ bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length,
/*
* Communication failure by device side.
* Possibly, it was forcibly suspended and resumed.
*
* For card reader with interrupt transfer support, ideally,
* removal is detected by intr_cb, but some card reader
* (e.g. SPR532) has a case of missing report to intr_cb.
*/
if (handle->ep_intr < 0 || handle->id_vendor == VENDOR_SCM)
if (handle->ep_intr < 0)
{
DEBUGOUT ("CCID: card inactive/removed\n");
handle->powered_off = 1;
}
#if defined(GNUPG_MAJOR_VERSION)
scd_kick_the_loop ();
#endif
}
}
return rc;
}
@ -2439,10 +2454,7 @@ ccid_slot_status (ccid_driver_t handle, int *statusbits, int on_wire)
/* Setup interrupt transfer at the initial call of slot_status
with ON_WIRE == 0 */
if (handle->transfer == NULL)
{
ccid_setup_intr (handle);
ccid_vendor_specific_setup (handle);
}
*statusbits = 0;
return 0;
@ -2911,6 +2923,7 @@ ccid_get_atr (ccid_driver_t handle,
DEBUGOUT_1 ("IFSD has been set to %d\n", tpdu[3]);
}
ccid_vendor_specific_setup (handle);
return 0;
}