Re: Race condition with SCardGetStatusChange() when USB Reader is removed
Maximilian Stein <[email protected]> Mon, 8 May 2017 12:47:02 +0200
| Newsgroups | gmane.comp.lib.muscle |
|---|---|
| Message-ID | <[email protected]> |
> Yes. It is possible.
> pcsc-lite may contain bugs.
I'm sorry if that sounded offensive. Personally I appreciate the work
and effort you put into this project very much and merely want to
contribute to its further improvement.
> I tried to reproduce the problem with the attached sample code but
> without success.
> I tried using the special reader "\\?PnP?\Notification" and also using
> the current reader name but could not reproduce the problem. Yes, I
> first applied your patch and I get the extra sleep() in pcscd.
>
> You can change line 52 of my sample code to use the PnP reader or the
> normal one.
On my testing machine (Xubuntu 16.04 python-pyscard installed from
repos) I can reproduce the problem with the python Unit Tests and your
sample code, with any value in line 52. But on another installation of
Ubuntu 16.04 (self compiled pyscard) I can't reproduce it either.
My patch includes a change in the lipcsclite client library which is
very important to provoke the race condition. This change should produce
debug output ("Waiting 2s to provoke...") when executing the test
programs with env variable PCSCLITE_DEBUG=0.
Did you get this additional client side debug output?
On the Ubuntu 16.04 machine I don't get the additional debug output, so
it seems like the pyscard Python module is not using the currently
installed libpcsclite. This is very strange because there is only the
self compiled libpcsclite installed. And with a test program written in
C, the problem is reproducible (including debug output) on both systems.
> Can you provide a/your sample code to reproduce the problem?
>
My test program in C is attached and should compile like this:
$ gcc -I/usr/local/include/PCSC/ SCardGetStatusChange_Disconnect.c -o
SCardGetStatusChange_Disconnect -lpcsclite
There has to be exactly one reader connected before starting the
program. SCardGetStatusChange is called 2 times with reader states for
both the PnP Notification and the connected reader. First call is to get
the current reader state. The second call is blocking waiting for
events. This call stays blocked even if the observed reader is removed.
Thanks for you efforts. I'm sorry that I didn't include a sample code
for reproduction in the first place. I could reproduce it using the
provided Unit tests (e.g. SCardGetStatusChange_PnP.py) and considered
this should be enough.
Best regards
Maximilian
_______________________________________________
Pcsclite-muscle mailing list
[email protected]
http://lists.alioth.debian.org/cgi-bin/mailman/listinfo/pcsclite-muscle
SCardGetStatusChange_Disconnect.c
(text/x-csrc, 4.9 KB)
/* * MUSCLE SmartCard Development ( http://pcsclite.alioth.debian.org/pcsclite.html ) * * Copyright (C) 1999 * David Corcoran <[email protected]> * Copyright (C) 2004-2010 * Ludovic Rousseau <[email protected]> * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** * @file * @brief This is a test program for pcsc-lite. */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <pcsclite.h> #include <winscard.h> #define PANIC 0 #define DONT_PANIC 1 #define BLUE "\33[34m" #define RED "\33[31m" #define BRIGHT_RED "\33[01;31m" #define GREEN "\33[32m" #define NORMAL "\33[0m" #define MAGENTA "\33[35m" static void test_rv(LONG rv, SCARDCONTEXT hContext, int dont_panic) { if (rv != SCARD_S_SUCCESS) { if (dont_panic) printf(BLUE "%s (don't panic)\n" NORMAL, pcsc_stringify_error(rv)); else { printf(RED "%s\n" NORMAL, pcsc_stringify_error(rv)); (void)SCardReleaseContext(hContext); exit(-1); } } else (void)puts(pcsc_stringify_error(rv)); } int main(/*@unused@*/ int argc, /*@unused@*/ char **argv) { SCARDHANDLE hCard; SCARDCONTEXT hContext; SCARD_READERSTATE rgReaderStates[2]; DWORD dwReaderLen, dwState, dwProt, dwAtrLen; DWORD dwReaders = 0; char *mszReaders = NULL; unsigned char *pbAtr = NULL; char *mszGroups; long rv; DWORD i; int p, iReader; int iList[16] = {0}; (void)argc; (void)argv; printf("\nTest race condition in SCardGetStatusChange on USB reader disconnect\n\n"); printf("Testing SCardEstablishContext\t: "); rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext); test_rv(rv, hContext, PANIC); printf("Testing SCardListReaders\t: "); mszGroups = NULL; dwReaders = SCARD_AUTOALLOCATE; rv = SCardListReaders(hContext, mszGroups, (LPSTR)&mszReaders, &dwReaders); test_rv(rv, hContext, DONT_PANIC); /* * Have to understand the multi-string here */ p = 0; for (i = 0; i+1 < dwReaders; i++) { ++p; printf(GREEN "Reader %02d: %s\n" NORMAL, p, &mszReaders[i]); iList[p] = i; while (mszReaders[++i] != 0) ; } if (p != 1) { printf(RED "Please connect exactly 1 reader\n" NORMAL); goto end; } /* Observe PnP Notification */ rgReaderStates[0].szReader = "\\\\?PnP?\\Notification"; rgReaderStates[0].dwCurrentState = SCARD_STATE_UNAWARE; /* Observe connected reader */ rgReaderStates[1].szReader = &mszReaders[iList[0]]; rgReaderStates[1].dwCurrentState = SCARD_STATE_UNKNOWN; printf("First SCardGetStatusChange to get reader state - expected to return\n"); (void)fflush(stdout); rv = SCardGetStatusChange(hContext, INFINITE, rgReaderStates, 2); test_rv(rv, hContext, PANIC); printf(GREEN "Reader %s - event state: %08lX\n" NORMAL, rgReaderStates[0].szReader, rgReaderStates[0].dwEventState); printf(GREEN "Reader %s - event state: %08lX\n" NORMAL, rgReaderStates[1].szReader, rgReaderStates[1].dwEventState); rgReaderStates[0].dwCurrentState = SCARD_STATE_UNAWARE; rgReaderStates[1].dwCurrentState = rgReaderStates[1].dwEventState; rgReaderStates[1].dwEventState = 0; printf("Second SCardGetStatusChange waiting for reader disconnect - expected to block until timeout\n"); (void)fflush(stdout); rv = SCardGetStatusChange(hContext, INFINITE, rgReaderStates, 2); test_rv(rv, hContext, PANIC); printf(GREEN "Reader %s - event state: %08lX\n" NORMAL, rgReaderStates[0].szReader, rgReaderStates[0].dwEventState); printf(GREEN "Reader %s - event state: %08lX\n" NORMAL, rgReaderStates[1].szReader, rgReaderStates[1].dwEventState); end: printf("Testing SCardFreeMemory\t\t: "); rv = SCardFreeMemory(hContext, mszReaders); test_rv(rv, hContext, PANIC); printf("Testing SCardReleaseContext\t: "); rv = SCardReleaseContext(hContext); test_rv(rv, hContext, PANIC); return 0; }