freenode
Kernel & Low-Level

Linux usbio driver fixed for slab overflows and I2C hang

Unchecked endpoint sizes and debug dumps left the Intel USB-to-I2C bridge open to memory corruption, hangs, and log leaks.

Three bugs in the Linux kernel usbio driver, which exposes I2C over USB for certain Intel and related bridges, have been fixed after code review found slab out-of-bounds accesses and a potential uninterruptible hang.

He Wei turned up the problems while re-examining the area around an earlier out-of-bounds read fix. The driver derived buffer sizes from bulk and control endpoint wMaxPacketSize values that the USB core only clamps downward. Length checks then subtracted a protocol header from a u16 using size_t arithmetic. Any endpoint smaller than the header wrapped the limit to a huge value, disabling the check. A device advertising a one-byte bulk endpoint could therefore overflow a one-byte slab object on the first I2C transfer, with length and contents influenced by whoever can issue I2C traffic, before any URB was submitted.

The same style of wrap in the I2C client produced a zero chunk size. The split-read loop never advanced, spinning indefinitely while holding the bridge mutex if the device kept answering, and blocking every other user of the adapter. Bridges whose bulk packets are smaller than 11 bytes will now be denied an I2C adapter at probe; such hardware could never complete a transfer in any case.

A third bug needed no malformed descriptor. Debug hex dumps of control and bulk replies used a device-supplied length that hex formatting caps at 64 bytes without regard to the real buffer. That read past the end of every ordinary low-, full-, and high-speed endpoint buffer and, with debug enabled, could spill adjacent slab contents into the kernel log during enumeration.

Probe-time validation now rejects the unsafe sizes. Supported bridges are unaffected. The changes are aimed at stable kernels as well.