Thursday, November 26, 2015

OS X El Capitan bug: PC/SC not usable after fork()

This is part of the series: "OS X El Capitan and smart cards: known bugs".

PC/SC is not unusable after fork()

SCardEstablishContext() returns SCARD_E_NO_SERVICE if called after fork(2) on El Capitan.

I can agree that if you mix PC/SC calls from before and after the fork(2) call you can have problems, as in OS X Yosemite bug: PC/SC functions crash after a fork(2). But if you start all the PC/SC calls in the same (child) process I expected it to work.

From the fork(2) manpage I read:

CAVEATS
There are limits to what you can do in the child process. To be totally safe you should restrict yourself to only executing async-signal safe operations until such time as one of the exec functions is called. All APIs, including global data symbols, in any framework or library should be assumed to be unsafe after a fork() unless explicitly documented to be safe or async-signal safe. If you need to use these frameworks in the child process, you must exec. In this situation it is reasonable to exec yourself.

I expect Apple to just close this bug as it it the documented behaviour.

It is not a bug but a feature ☹.

See also

Apple bug report #23669488 "PC/SC is not unusable after fork()"

Bug closed by Apple. See Update bellow.

Sample code


#include <stdio.h>
#include <unistd.h>
#ifdef __APPLE__
#include <PCSC/winscard.h>
#include <PCSC/wintypes.h>
#else
#include <winscard.h>
#endif

int main(void)
{
    int pid = fork();
    if (0 == pid)
    {
        /* son process */

        SCARDCONTEXT hContext;
        DWORD err = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL,
            &hContext);
        if (err != SCARD_S_SUCCESS) {
            printf("ScardEstablishedContext: %s (0x%08lx)\n",
                pcsc_stringify_error(err), (long)err);
            return -1;
        }
        else
            printf("OK\n");

        SCardReleaseContext(hContext);
    }
    else
        /* give some time to the son */
        sleep(1);

    return 0;
}


Result (on El Capitan)

$ CFLAGS="-framework PCSC" make main
cc -framework PCSC    main.c   -o main

$ ./main
ScardEstablishedContext: Service not available. (0x8010001d)

Expected result (on Debian)

$ CFLAGS=`pkg-config --cflags libpcsclite` LDFLAGS=`pkg-config --libs libpcsclite` make main
cc -pthread -I/usr/include/PCSC    -lpcsclite    main.c   -o main

$ ./main
OK

Known workaround

None known.

Update 8th December 2015

As expected Apple closed the bug with:
As documented in the quoted fork man page excerpt, it is quite expected that PC/SC does not work in forked child.