The problem
pcsc-lite is composed of two parts:
- a daemon
pcscd
The daemon job is to access/send commands to the readers, through reader drivers.
- a library
libpcsclite.so.1
The library provides the PC/SC API to the application to talk to the pcscd
daemon using an internal protocol.
Traditionally the daemon is started when the system starts and is running until the system is shut down.
Using the dependencies relation of packages in modern distributions you may install a package that, in some cases, uses PC/SC and then is linked with
libpcsclite
and then
pcscd
is also installed and running all the time for nothing.
The solution
The idea is to start
pcscd
only when needed. It is possible since the first PC/SC call is always
SCardEstablishContext()
. So
SCardEstablishContext()
must check if
pcscd
is already running and launch it if not.
The implementation details
pcscd exit
It is also possible to exit
pcscd
when no more client is using it. This is possible since the last PC/SC call is always
SCardReleaseContext()
.
When all the contexts open with
SCardEstablishContext()
have been closed by
SCardReleaseContext()
it is possible to exit
pcscd
. To avoid restarting
pcscd
just after exiting it,
pcscd
exits only after 60 seconds of inactivity. It is configurable using:
#define TIME_BEFORE_SUICIDE 60
Reader devices access rights
By default (on GNU/Linux) USB devices are accessible (for write accesses) by root processes only. If
pcscd
is started during the system start up the process is executed as root so has the correct permissions to access the USB devices. But if now
pcscd
is started by a process of a normal user it will be started with the access rights of this normal user.
pcscd
then needs to gain extra access rights. This is the perfect use of the suid/sgid mechanism. In pcsc-lite 1.6.x (with x < 5) the file
/usr/sbin/pcscd
was suid root. So the process was running as root. It does work but programs running as root are always "suspicious" for a security aware administrator. And it is even more important if the program is suid root, as it was the case.
To be conform to the principle of least privilege a better approach has been implemented. The access rights of the devices are changed to be accessible in read and write to a process in the group "pcscd", and
pcscd
is now a sgid program in the group "pcscd". So when
pcscd
is started by a normal user it will gain access to files in the group "pcscd".
The group "pcscd" should be used only by pcsc-lite so only
pcscd
has access to smart card readers. The
pcscd
process has only gained the minimum rights needed to do its job (instead of gaining root access).
udev rule
To change the access rights of a USB devices the solution on a GNU/Linux system is to write a
udev rule file.
The CCID driver provides such a
udev rule file.
The main part of the file is:
# If not adding the device, go away
ACTION!="add", GOTO="pcscd_ccid_rules_end"
SUBSYSTEM!="usb", GOTO="pcscd_ccid_rules_end"
ENV{DEVTYPE}!="usb_device", GOTO="pcscd_ccid_rules_end"
# generic CCID device
ATTRS{bInterfaceClass}=="0b", RUN+="/bin/chgrp pcscd $root/$parent"
# All done
LABEL="pcscd_ccid_rules_end"
If a device has an interface with the field bInterfaceClass set to 0x0b (11 in decimal) then it is a CCID device according to the CCID specification. In that case run the command
chgrp
to set the group to
pcscd
to the parent device.
udev has a
GROUP=
action to change the group of a device but it looks like I can't use that. The rule matches a field of an interface but
GROUP=
works when matching a device (the parent of an interface).
Reader driver impacts
The reader drivers have to provide a udev rule to change the group ownership of the device supported by the driver. If they do not the devices will not be accessible unless pcscd is run as root (as before).
For example the
ifd-gempc driver will have to provide a udev rule for the 3 USB devices supported.
Something like:
# udev rules to set the access rights of GemPC smart card readers
# so they can be used by pcscd
# If not adding the device, go away
ACTION!="add", GOTO="pcscd_ifd_gempc_rules_end"
SUBSYSTEM!="usb", GOTO="pcscd_ifd_gempc_rules_end"
# GemPC 430, 432 & 435 USB readers
ATTRS{idVendor}=="08e6", ATTRS{idProduct}=="0430", GROUP="pcscd"
ATTRS{idVendor}=="08e6", ATTRS{idProduct}=="0432", GROUP="pcscd"
ATTRS{idVendor}=="08e6", ATTRS{idProduct}=="0435", GROUP="pcscd"
# All done
LABEL="pcscd_ifd_gempc_rules_end"
The file is easy to generate since you just have to reuse the information from the
Info.plist
file of the driver.
The rule file for the CCID driver is a bit different since I used the fact that CCID devices all have the same USB class (bInterfaceClass).
Security aspects
Possible security vulnerability in pcscd
I know no security vulnerability in pcscd. But pcscd is not immune. See
pcsc-lite security advisory CVE-2010-0407 for example.
If a new security vulnerability in pcscd is found the impact will be much lower now that pcscd run as a simple user in group "pcscd". An attacker would not gain root access.
Multi user systems
What will happen on a system with users A and B that both want to use PC/SC?
Suppose A starts a PC/SC program and then starts the
pcscd
daemon.
pcscd
will run as user A with the group set to pcscd.
Then B starts a PC/SC program.
pcscd
is already running so it will not be restarted.
B could try to inject code in the pcscd process and run the code with the access rights of A. This should not be possible. See the previous chapter about possible vulnerability in pcscd.
User A could run pcscd in debug mode (using the
--debug
and
--apdu
option of
pcscd
) and see all the PC/SC commands and APDU used by the application run by B. Such APDU could contain the pincode of B for example. This attack is not possible. pcscd contains a check to disable the
--apdu
option if it has been launched using the sgid mechanism.
Conclusion
The auto start mechanism introduced in pcsc-lite 1.6.0 allows to limit the number of running processes (when a smart card is not used).
The sgid mechanism introduced in pcsc-lite 1.6.5 greatly limits the security implication by just using a special group instead of running pcscd as root.