Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0026e005 authored by Alan Stern's avatar Alan Stern Committed by Greg Kroah-Hartman
Browse files

USB: fix bug in initialization of interface minor numbers



Recent changes in the usbhid layer exposed a bug in usbcore.  If
CONFIG_USB_DYNAMIC_MINORS is enabled then an interface may be assigned
a minor number of 0.  However interfaces that aren't registered as USB
class devices also have their minor number set to 0, during
initialization.  As a result usb_find_interface() may return the
wrong interface, leading to a crash.

This patch (as1418) fixes the problem by initializing every
interface's minor number to -1.  It also cleans up the
usb_register_dev() function, which besides being somewhat awkwardly
written, does not unwind completely on all its error paths.

Signed-off-by: default avatarAlan Stern <stern@rowland.harvard.edu>
Tested-by: default avatarPhilip J. Turmel <philip@turmel.org>
Tested-by: default avatarGabriel Craciunescu <nix.or.die@googlemail.com>
Tested-by: default avatarAlex Riesen <raa.lkml@gmail.com>
Tested-by: default avatarMatthias Bayer <jackdachef@gmail.com>
CC: Jiri Kosina <jkosina@suse.cz>
Cc: stable <stable@kernel.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent a850ea30
Loading
Loading
Loading
Loading
+16 −19
Original line number Diff line number Diff line
@@ -159,9 +159,9 @@ void usb_major_cleanup(void)
int usb_register_dev(struct usb_interface *intf,
		     struct usb_class_driver *class_driver)
{
	int retval = -EINVAL;
	int retval;
	int minor_base = class_driver->minor_base;
	int minor = 0;
	int minor;
	char name[20];
	char *temp;

@@ -173,12 +173,17 @@ int usb_register_dev(struct usb_interface *intf,
	 */
	minor_base = 0;
#endif
	intf->minor = -1;

	dbg ("looking for a minor, starting at %d", minor_base);

	if (class_driver->fops == NULL)
		goto exit;
		return -EINVAL;
	if (intf->minor >= 0)
		return -EADDRINUSE;

	retval = init_usb_class();
	if (retval)
		return retval;

	dev_dbg(&intf->dev, "looking for a minor, starting at %d", minor_base);

	down_write(&minor_rwsem);
	for (minor = minor_base; minor < MAX_USB_MINORS; ++minor) {
@@ -186,20 +191,12 @@ int usb_register_dev(struct usb_interface *intf,
			continue;

		usb_minors[minor] = class_driver->fops;

		retval = 0;
		intf->minor = minor;
		break;
	}
	up_write(&minor_rwsem);

	if (retval)
		goto exit;

	retval = init_usb_class();
	if (retval)
		goto exit;

	intf->minor = minor;
	if (intf->minor < 0)
		return -EXFULL;

	/* create a usb class device for this usb interface */
	snprintf(name, sizeof(name), class_driver->name, minor - minor_base);
@@ -213,11 +210,11 @@ int usb_register_dev(struct usb_interface *intf,
				      "%s", temp);
	if (IS_ERR(intf->usb_dev)) {
		down_write(&minor_rwsem);
		usb_minors[intf->minor] = NULL;
		usb_minors[minor] = NULL;
		intf->minor = -1;
		up_write(&minor_rwsem);
		retval = PTR_ERR(intf->usb_dev);
	}
exit:
	return retval;
}
EXPORT_SYMBOL_GPL(usb_register_dev);
+1 −0
Original line number Diff line number Diff line
@@ -1802,6 +1802,7 @@ free_interfaces:
		intf->dev.groups = usb_interface_groups;
		intf->dev.dma_mask = dev->dev.dma_mask;
		INIT_WORK(&intf->reset_ws, __usb_queue_reset_device);
		intf->minor = -1;
		device_initialize(&intf->dev);
		dev_set_name(&intf->dev, "%d-%s:%d.%d",
			dev->bus->busnum, dev->devpath,