At the recent Ubuntu Developer Summit, I managed to convince a few people (after assurances that there would be no permanent damage) to plug a USB stick into their machines so we could watch Xorg crash and wedge their console. What was this evil thing, you ask? It was an AVR microprocessor connected to USB, acting as a USB HID Keyboard, with the product name set to “%n”.
Recently a Chrome OS developer discovered that renaming his Bluetooth Keyboard to “%n” would crash Xorg. The flaw was in the logging stack, triggering glibc to abort the process due to format string protections. At first glance, it looks like this isn’t a big deal since one would have to have already done a Bluetooth pairing with the keyboard, but it would be a problem for any input device, not just Bluetooth. I wanted to see this in action for a “normal” (USB) keyboard.
I borrowed a “Maximus” USB AVR from a friend, and then ultimately bought a Minimus. It will let you put anything you want on the USB bus.
I added a rule for it to udev:
SUBSYSTEM=="usb", ACTION=="add", ATTR{idVendor}=="03eb", ATTR{idProduct}=="*", GROUP="plugdev"
installed the AVR tools:
sudo apt-get install dfu-programmer gcc-avr avr-libc
and pulled down the excellent LUFA USB tree:
git clone git://github.com/abcminiuser/lufa-lib.git
After applying a patch to the LUFA USB keyboard demo, I had my handy USB-AVR-as-Keyboard stick ready to crash Xorg:
- .VendorID = 0x03EB, - .ProductID = 0x2042, + .VendorID = 0x045e, + .ProductID = 0x000b, ... - .UnicodeString = L"LUFA Keyboard Demo" + .UnicodeString = L"Keyboard (%n%n%n%n)"
In fact, it was so successfully that after I got the code right and programmed it, Xorg immediately crashed on my development machine. :)
make dfu
After a reboot, I switched it back to programming mode by pressing and holding the “H” button, press/releasing the “R” button, and releasing “H”.
The fix to Xorg is winding its way through upstream, and should land in your distros soon. In the meantime, you can disable your external USB ports, as Marc Deslauriers demonstrated for me:
echo "0" > /sys/bus/usb/devices/usb1/authorized echo "0" > /sys/bus/usb/devices/usb1/authorized_default
Be careful of shared internal/external ports, and having two buses on one port, etc.
© 2012, Kees Cook. This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 License.