[patch]race between open and disconnect in usbhid

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



There is a window:

task A					task B
spin_lock_irq(&usbhid->inlock);	/* Sync with error handler */
usb_set_intfdata(intf, NULL);
spin_unlock_irq(&usbhid->inlock);
usb_kill_urb(usbhid->urbin);
usb_kill_urb(usbhid->urbout);
usb_kill_urb(usbhid->urbctrl);

del_timer_sync(&usbhid->io_retry);
cancel_work_sync(&usbhid->reset_work);

						if (!hid->open++) {
							res = usb_autopm_get_interface(usbhid->intf);
							if (res < 0) {
								hid->open--;
								return -EIO;
							}
						}
						if (hid_start_in(hid))

if (hid->claimed & HID_CLAIMED_INPUT)
	hidinput_disconnect(hid);

in which an open() to an already disconnected device will submit an URB
to an undead device. In case disconnect() was called by an ioctl, this'll
oops. Fix by introducing a reliable flag an checking it in hid_start_in().

Signed-off-by: Oliver Neukum <oneukum@xxxxxxx>

----

--- linux-2.6.25-rc7-vanilla/drivers/hid/usbhid/usbhid.h	2007-07-09 01:32:17.000000000 +0200
+++ linux-2.6.25-rc7-work/drivers/hid/usbhid/usbhid.h	2008-03-31 13:45:25.000000000 +0200
@@ -77,6 +77,7 @@
 	unsigned long stop_retry;                                       /* Time to give up, in jiffies */
 	unsigned int retry_delay;                                       /* Delay length in ms */
 	struct work_struct reset_work;                                  /* Task context for resets */
+	char disconnected:1;						/* indicates undead device - no use */
 
 };
 
--- linux-2.6.25-rc7-vanilla/drivers/hid/usbhid/hid-core.c	2008-03-31 15:20:58.000000000 +0200
+++ linux-2.6.25-rc7-work/drivers/hid/usbhid/hid-core.c	2008-03-31 13:45:10.000000000 +0200
@@ -82,6 +82,7 @@
 
 	spin_lock_irqsave(&usbhid->inlock, flags);
 	if (hid->open > 0 && !test_bit(HID_SUSPENDED, &usbhid->iofl) &&
+			!usbhid->disconnected &&
 			!test_and_set_bit(HID_IN_RUNNING, &usbhid->iofl)) {
 		rc = usb_submit_urb(usbhid->urbin, GFP_ATOMIC);
 		if (rc != 0)
@@ -155,7 +156,7 @@
 	spin_lock_irqsave(&usbhid->inlock, flags);
 
 	/* Stop when disconnected */
-	if (usb_get_intfdata(usbhid->intf) == NULL)
+	if (usbhid->disconnected)
 		goto done;
 
 	/* If it has been a while since the last error, we'll assume
@@ -932,6 +933,7 @@
 
 	spin_lock_irq(&usbhid->inlock);	/* Sync with error handler */
 	usb_set_intfdata(intf, NULL);
+	usbhid->disconnected = 1;
 	spin_unlock_irq(&usbhid->inlock);
 	usb_kill_urb(usbhid->urbin);
 	usb_kill_urb(usbhid->urbout);
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Media Devel]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Linux Wireless Networking]     [Linux Omap]

  Powered by Linux