@@ -764,8 +764,13 @@ static int claimintf(struct usb_dev_state *ps, unsigned int ifnum)
intf = usb_ifnum_to_if(dev, ifnum);
if (!intf)
err = -ENOENT;
- else
+ else {
+ /* suppress uevents for devices handled by usbfs */
+ dev_set_uevent_suppress(&intf->dev, 1);
err = usb_driver_claim_interface(&usbfs_driver, intf, ps);
+ if (err != 0)
+ dev_set_uevent_suppress(&intf->dev, 0);
+ }
if (err == 0)
set_bit(ifnum, &ps->ifclaimed);
return err;
@@ -594,6 +594,8 @@ void usb_driver_release_interface(struct usb_driver *driver,
*/
if (device_is_registered(dev)) {
device_release_driver(dev);
+ /* make sure we allow uevents again */
+ dev_set_uevent_suppress(dev, 0);
} else {
device_lock(dev);
usb_unbind_interface(dev);
commit 1455cf8dbfd0 ("driver core: emit uevents when device is bound to a driver") added bind/unbind uevents when a driver is bound/unbound to a physical device. For USB devices which are handled via the generic usbfs layer (via libusb for example), this is problematic: Each time a user space program calls ioctl(usb_fd, USBDEVFS_CLAIMINTERFACE, &usb_intf_nr); and then later ioctl(usb_fd, USBDEVFS_RELEASEINTERFACE, &usb_intf_nr); The kernel will now produce a bind/unbind event, which does not really contain any useful information. This allows a user space program to run a DoS attack against programs which listen to uevents (in particular systemd/eudev/upowerd): A malicious user space program just has to call in a tight loop ioctl(usb_fd, USBDEVFS_CLAIMINTERFACE, &usb_intf_nr); ioctl(usb_fd, USBDEVFS_RELEASEINTERFACE, &usb_intf_nr); With this loop the malicious user space program floods the kernel and all programs listening to uevents with tons of bind/unbind events. This patch suppresses uevents for interfaces claimed via usbfs. Signed-off-by: Ingo Rohloff <ingo.rohloff@lauterbach.com> --- drivers/usb/core/devio.c | 7 ++++++- drivers/usb/core/driver.c | 2 ++ 2 files changed, 8 insertions(+), 1 deletion(-)