Friday, December 12, 2014

OS X Yosemite bug: SCardTransmit (pioSendPci not checked)

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

SCardTransmit

SCardTransmit() fails to detect wrong value for pioSendPci parameter.

If you use NULL for pioSendPci parameter then you get a crash (Segmentation fault: 11) of the application instead of getting the error 0x80100004 that is SCARD_E_INVALID_PARAMETER.

See also

Apple bug report #19231406 "PC/SC function SCardTransmit: pioSendPci not checked".

Sample code

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

int main(int argc, const char * argv[]) {
    SCARDCONTEXT hContext;
    LPSTR mszReaders;
    DWORD err = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext);
    if (err != SCARD_S_SUCCESS) {
        printf("ScardEstablishedContext : %08x\n",err);
  return -1;
    }

 DWORD cchReaders = 0;
 err = SCardListReaders(hContext, "SCard$AllReaders", NULL, &cchReaders);
 if (err != 0) {
  printf("ScardListReaders : %08x\n",err);
  return -1;
 }
 mszReaders = calloc(cchReaders, sizeof(char));
 if (!mszReaders) {
  printf("calloc\n");
  return -1;
 }
 err = SCardListReaders(hContext,"SCard$AllReaders", mszReaders, &cchReaders);
 if (err != SCARD_S_SUCCESS) {
  printf("ScardListReaders : %08x\n",err);
  return -1;
 }

 printf("Reader : %s\n", mszReaders);

 SCARDHANDLE hCard;
 DWORD dwActiveProtocol;
 err = SCardConnect(hContext, mszReaders, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &hCard, &dwActiveProtocol);
 unsigned char cmd[] = {0, 0, 0, 0, 0};
 unsigned char resp[255];
 DWORD resp_len = sizeof resp;

 err = SCardTransmit(hCard, NULL, cmd, sizeof cmd, NULL, resp, &resp_len);
 if (err != SCARD_S_SUCCESS) {
  printf("ScardTransmit : %08x\n",err);
  return -1;
 }

 SCardDisconnect(hCard, SCARD_LEAVE_CARD);
 SCardReleaseContext(hContext);

    return 0;
}

Result (on Yosemite)

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

$ ./main
Reader : Gemalto PC Twin Reader
Segmentation fault: 11

$ lldb ./main
(lldb) target create "./main"
Current executable set to './main' (x86_64).
(lldb) r
Process 6169 launched: './main' (x86_64)
Reader : Gemalto PC Twin Reader
Process 6169 stopped
* thread #1: tid = 0x7472a, 0x0000000100004b6d PCSC`__SCardTransmit_block_invoke + 17, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x0)
    frame #0: 0x0000000100004b6d PCSC`__SCardTransmit_block_invoke + 17
PCSC`__SCardTransmit_block_invoke + 17:
-> 0x100004b6d:  movl   (%rax), %edx
   0x100004b6f:  leaq   0x6901(%rip), %rsi        ; "proto"
   0x100004b76:  movq   %r14, %rdi
   0x100004b79:  callq  0x10000b0c2               ; symbol stub for: xpc_dictionary_set_uint64

Expected result (on Debian)

CFLAGS=`pkg-config --cflags libpcsclite` LDFLAGS=`pkg-config --libs libpcsclite` make main

$ ./main
Reader : Gemalto PC Twin Reader (70D7E2EE) 00 00
ScardTransmit : 80100004

Known workaround

Do not use NULL for pioSendPci. It is a wrong value.

Update

This bug is now fixed in Mac OS X El Capitan 10.11.0.