Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

usb: usbfs: Suppress problematic bind and unbind uevents.

commit 1455cf8dbfd0 ("driver core: emit uevents when device is bound
to a driver") added bind and unbind uevents when a driver is bound or
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 or 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 and unbind
events.

This patch suppresses uevents for ioctls USBDEVFS_CLAIMINTERFACE and
USBDEVFS_RELEASEINTERFACE.

Signed-off-by: Ingo Rohloff <ingo.rohloff@lauterbach.com>
Link: https://lore.kernel.org/r/20191011115518.2801-1-ingo.rohloff@lauterbach.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Ingo Rohloff and committed by
Greg Kroah-Hartman
abb0b3d9 be731286

+14 -1
+14 -1
drivers/usb/core/devio.c
··· 764 764 intf = usb_ifnum_to_if(dev, ifnum); 765 765 if (!intf) 766 766 err = -ENOENT; 767 - else 767 + else { 768 + unsigned int old_suppress; 769 + 770 + /* suppress uevents while claiming interface */ 771 + old_suppress = dev_get_uevent_suppress(&intf->dev); 772 + dev_set_uevent_suppress(&intf->dev, 1); 768 773 err = usb_driver_claim_interface(&usbfs_driver, intf, ps); 774 + dev_set_uevent_suppress(&intf->dev, old_suppress); 775 + } 769 776 if (err == 0) 770 777 set_bit(ifnum, &ps->ifclaimed); 771 778 return err; ··· 792 785 if (!intf) 793 786 err = -ENOENT; 794 787 else if (test_and_clear_bit(ifnum, &ps->ifclaimed)) { 788 + unsigned int old_suppress; 789 + 790 + /* suppress uevents while releasing interface */ 791 + old_suppress = dev_get_uevent_suppress(&intf->dev); 792 + dev_set_uevent_suppress(&intf->dev, 1); 795 793 usb_driver_release_interface(&usbfs_driver, intf); 794 + dev_set_uevent_suppress(&intf->dev, old_suppress); 796 795 err = 0; 797 796 } 798 797 return err;