Snooping the USB Data Stream

Follow along with the kernel hacker's actual problem-solving process as the quest to add support for a new device begins.

Day 1: I open the box to see a small USB device—no bigger
than a quarter—a CD and a note from my editor,
“Make this work on Linux!” “Okay”, I think,
“this
should be easy.”

Figure 1. MARX Software Security's CrypToken

I plug the device in to my laptop and run a small
program called usbview to learn what the Linux
kernel thinks this device is (Figure 2). This
device must be calling itself a USB CrypToken, as
that is the string contained in the device.
Unfortunately, the device name is in red, which means
no kernel driver is bound to the device.
I either have to write one or find a way to
use libusb to talk to the device from user space (see
my article “Writing a Real Driver—in User Space”,
LJ, June 2004, for more information about libusb).

Figure 2. usbview identifies the device by vendor and product ID.

Not content to rely on pretty GUI programs, I poke
around in the /proc/bus/usb/devices file to get the
raw device information. The section that describes
this device looks like this:

Curious to know whether any other Linux user has tried
this device, I consult the Linux USB Working
Devices List (see the on-line Resources section). Plugging the vendor
ID of 0d7a in to the Quick Search field results in
no records found. Perhaps this project will take more work
than I thought.

Day 2: The CD, where did I toss it? I locate it and put it
in the drive and, look, there's a file called
linux.txt on it. Wow, a vendor that acknowledges
that Linux might be a viable operating system to
support—things sure have changed over the years.
After poking around further and reading the
documentation on the CD, I realize the device
is a small crypto token that can be used to do all
sorts of fun things, such as
read a unique serial number from the device (each device is
different),
encrypt data through the device with a 128-bit
key stored only in the device and
save data on the device in a secure storage area.

On the CD is a shared library that can be used
to talk to the USB device to allow a program to access
the functions provided by this device. Also
present is a small test program that shows how the
different library functions work. The library uses
libusb to talk directly to the device from
user space, which means that a kernel driver is not
necessary for this device.
The library's license does not allow it to
be used within a program that would be licensed under
the GPL, however, which is unfortunate for many potential uses.
I need to find some way to allow GPL programs to talk
to the USB device.

Day 3: While rummaging through my old collection of USB patches, I
dig up a reference to a developer who modified the
kernel usbfs core code to log all data that flows
through it. This patch would allow anyone to read the raw
USB data for any program that uses usbfs to talk to
a USB device. Because libusb uses usbfs to
communicate with USB devices, this might offer a way
to reverse engineer this device.
Unfortunately, the patch wasn't present with the
reference, and no amount of digging on the Internet
turned up any real code.

Day 4: As there is no available patch to do what I want to
do, I might as well do it myself. So, off to grab the
latest 2.6 kernel source tree and dive in.

The files inode.c, devices.c and devio.c in the
drivers/usb/core/ directory of the kernel source
tree implement the usbfs filesystem.
The main filesystem
code is in the inode.c file. It contains all of the
various VFS code that creates a virtual filesystem
and the virtual files within it. The file devices.c
handles the creation and reading of the
/proc/bus/usb/devices file. This file shows all USB
devices and information for those devices in the
system at the present time.

The file devio.c controls the raw access of USB
devices through the usbfs filesystem. For a
user-space program to talk to a USB device through
usbfs, it needs to use the ioctl() command on a file that
represents the USB device. All of the different
ioctl messages that can be sent to the USB devices
through usbfs are detailed in the
include/linux/usbdevfs.h file.

So, in order to log all accesses to all devices
through usbfs, the devio.c file should be modified.
Digging into the file, the function usbdev_ioctl
looked like the proper place to do this logging. It
is called for every ioctl call to a usbfs file.
Within that function is a big switch statement that
calls the proper functions, depending on the
different ioctl command. That is the perfect place
to log what kind of command was sent to the device.
So, I added a simple printk() call to each case
statement, causing them to look like this:

A simple compile, install and module load later
confirmed that every usbfs access is now logged to
the kernel log, which can be seen by running the
dmesg program. I determined that running the
lsusb program as lsusb -v
produced a lot of usbfs accesses as the program
retrieves all of the raw USB configuration data from
all devices.

Day 5: Now that the different kinds of usbfs accesses can
be noticed easily, it is time to log the data
these accesses generate. In looking at the
description of the device in the
/proc/bus/usb/devices file, it appears that I care only
about the accesses to the control endpoint,
because there are no endpoints assigned to this
device.

Digging further into the devio.c file, I determine
that the proc_control() function handles all control
messages. There, the code determines whether the request
is a read or write control message with the code:

if (ctrl.bRequestType & 0x80) {

The USB bRequestType variable is a bitfield, and
the uppermost bit determines the direction of the
request. So, in the read section of this if
statement I add the lines:

How do you enable this on the fly with the FC2 2.6.8-1.521 kernel? It appears that usbcore is built into the kernel since modprobe usbcore says it is not found. /sys//module/usbcore does not exist either. Matter of fact I cant find any tunable parameters in any of the directories under /sys/module/.

Trending Topics

Webinar: 8 Signs You’re Beyond Cron

Scheduling Crontabs With an Enterprise Scheduler
11am CDT, April 29th

Join Linux Journal and Pat Cameron, Director of Automation Technology at HelpSystems, as they discuss the eight primary advantages of moving beyond cron job scheduling. In this webinar, you’ll learn about integrating cron with an enterprise scheduler.