Commit cba64672 authored by Ingo Rohloff's avatar Ingo Rohloff Committed by Greg Kroah-Hartman

usb: usbfs: Suppress problematic bind and unbind uevents.

[ Upstream commit abb0b3d9 ]

commit 1455cf8d ("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: default avatarIngo Rohloff <ingo.rohloff@lauterbach.com>
Link: https://lore.kernel.org/r/20191011115518.2801-1-ingo.rohloff@lauterbach.comSigned-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
parent 888d90b3
...@@ -739,8 +739,15 @@ static int claimintf(struct usb_dev_state *ps, unsigned int ifnum) ...@@ -739,8 +739,15 @@ static int claimintf(struct usb_dev_state *ps, unsigned int ifnum)
intf = usb_ifnum_to_if(dev, ifnum); intf = usb_ifnum_to_if(dev, ifnum);
if (!intf) if (!intf)
err = -ENOENT; err = -ENOENT;
else else {
unsigned int old_suppress;
/* suppress uevents while claiming interface */
old_suppress = dev_get_uevent_suppress(&intf->dev);
dev_set_uevent_suppress(&intf->dev, 1);
err = usb_driver_claim_interface(&usbfs_driver, intf, ps); err = usb_driver_claim_interface(&usbfs_driver, intf, ps);
dev_set_uevent_suppress(&intf->dev, old_suppress);
}
if (err == 0) if (err == 0)
set_bit(ifnum, &ps->ifclaimed); set_bit(ifnum, &ps->ifclaimed);
return err; return err;
...@@ -760,7 +767,13 @@ static int releaseintf(struct usb_dev_state *ps, unsigned int ifnum) ...@@ -760,7 +767,13 @@ static int releaseintf(struct usb_dev_state *ps, unsigned int ifnum)
if (!intf) if (!intf)
err = -ENOENT; err = -ENOENT;
else if (test_and_clear_bit(ifnum, &ps->ifclaimed)) { else if (test_and_clear_bit(ifnum, &ps->ifclaimed)) {
unsigned int old_suppress;
/* suppress uevents while releasing interface */
old_suppress = dev_get_uevent_suppress(&intf->dev);
dev_set_uevent_suppress(&intf->dev, 1);
usb_driver_release_interface(&usbfs_driver, intf); usb_driver_release_interface(&usbfs_driver, intf);
dev_set_uevent_suppress(&intf->dev, old_suppress);
err = 0; err = 0;
} }
return err; return err;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment