From 780c38f16269367271c1fab94e4b6e9ad5a5279e Mon Sep 17 00:00:00 2001 From: wismna Date: Mon, 16 Jan 2017 11:29:35 -0500 Subject: [PATCH] Details on USB fingerprinting --- readme.md | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/readme.md b/readme.md index 23ba142..3e52bad 100644 --- a/readme.md +++ b/readme.md @@ -66,6 +66,28 @@ After a bit of fiddling around, it worked! My gadget was now automatically recognized by Windows and Linux, without having to change anything to the configuration files. But, as there is always a but, you may have noticed that I stopped talking about Mac... and this is because since version 10.11, MacOs is no longer smart enough to load the CDC ECM configuration if it isn't the first one! I now needed a way to make the gadget recognize the host it was connected to via USB fingerprinting, so that I could better configure libcomposite.

OS fingerprinting

-Coming soon... +This is where the fun began. I had two big issues to overcome: +
    +
  1. Find a way to dump, trace or sniff USB traffic on a USB controller set as a device
  2. +
  3. The chicken and the egg problem: to trace USB traffic, the gadget needed to be set up, but to be set up correctly, I needed to trace USB traffic...
  4. +
-Details can be found in the pi_startup.sh file. +The first thing to do was to find a way to dump incoming USB traffic. The obvious answer was to use the `usbmon` kernel module which allows tracing of USB data. Unfortunately, this doesn't work at all (no data is captured) when the USB controller is in device mode. But to create a USB gadget of any kind, the controller has to be set in device (or peripheral) mode. So no `usbmon`, and by way of consequence, no tcpdump, wireshark or whatever else uses `usbmon` traces.
+For device mode to work on the Raspberry Pi Zero, we have to load a kernel module, `dwc2`, which enables USB OTG (dynamic switching between host and device modes). I tried setting the module to act as a host to enable `usbmon` on it, but then no gadget would work, and there would be no trace. +After a lot of going around in circles, I decided to read the source of this module to understand how it worked. I found a function which handles the reception of USB Setup Requests, which is exactly what I was interested in. So I simply added a `printk()` function in there to output these requests in the kernel messages, which could then be seen by calling `dmesg`.
+Clearly, this is not the most elegant way to do it, but I: + + +So, I made my change, recompiled the module, replaced the standard one with this one, and finally! I could see the USB Setup Requests in dmesg. + +I now had to tackle on the next issue: the messages would only be shown when the gadget was initialized. But I wanted to see those messages before initializing the gadget so that it could be set properly! +So I got the idea: what if I loaded a "dummy" gadget at boot, let it generate USB trace data, then disable it and activate the "real" gadget?
+I tried at first creating another `libcomposite` gadget, but it wouldn't work properly. I then decided to load one of the legacy modules which was replaced by `libcomposite`, `g_ether`. Even though it was a legacy module, it would still work, and as added bonuses, it required no configuration at all and was loaded very early during boot. +I tested that, and it worked: the `g_ether`gadget was generating USB traffic in `dmesg`, which I would interpret to determine which OS the Raspberry Pi was connected to. + +Granted, at the time being, it is quite simple as it only allows recognizing MacOs among other OSs (which however is exactly what I needed), but it should be relatively easy to use this data to perform more precise USB fingerprinting. + +So, finally, after all this, I now have a Ethernet Gadget that is recognized and loaded, without any user interaction (no manual driver installation etc.) on all major OSs: Linux, MacOS and Windows!