aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2019-04-19 13:52:38 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2019-04-19 15:15:13 -0400
commitc2b71462d294cf517a0bc6e4fd6424d7cee5596f (patch)
treedf8fc206e13f52f2c4b174002ef42f2e9b51996f
parentfc834e607ae3d18e1a20bca3f9a2d7f52ea7a2be (diff)
USB: core: Fix bug caused by duplicate interface PM usage counter
The syzkaller fuzzer reported a bug in the USB hub driver which turned out to be caused by a negative runtime-PM usage counter. This allowed a hub to be runtime suspended at a time when the driver did not expect it. The symptom is a WARNING issued because the hub's status URB is submitted while it is already active: URB 0000000031fb463e submitted while active WARNING: CPU: 0 PID: 2917 at drivers/usb/core/urb.c:363 The negative runtime-PM usage count was caused by an unfortunate design decision made when runtime PM was first implemented for USB. At that time, USB class drivers were allowed to unbind from their interfaces without balancing the usage counter (i.e., leaving it with a positive count). The core code would take care of setting the counter back to 0 before allowing another driver to bind to the interface. Later on when runtime PM was implemented for the entire kernel, the opposite decision was made: Drivers were required to balance their runtime-PM get and put calls. In order to maintain backward compatibility, however, the USB subsystem adapted to the new implementation by keeping an independent usage counter for each interface and using it to automatically adjust the normal usage counter back to 0 whenever a driver was unbound. This approach involves duplicating information, but what is worse, it doesn't work properly in cases where a USB class driver delays decrementing the usage counter until after the driver's disconnect() routine has returned and the counter has been adjusted back to 0. Doing so would cause the usage counter to become negative. There's even a warning about this in the USB power management documentation! As it happens, this is exactly what the hub driver does. The kick_hub_wq() routine increments the runtime-PM usage counter, and the corresponding decrement is carried out by hub_event() in the context of the hub_wq work-queue thread. This work routine may sometimes run after the driver has been unbound from its interface, and when it does it causes the usage counter to go negative. It is not possible for hub_disconnect() to wait for a pending hub_event() call to finish, because hub_disconnect() is called with the device lock held and hub_event() acquires that lock. The only feasible fix is to reverse the original design decision: remove the duplicate interface-specific usage counter and require USB drivers to balance their runtime PM gets and puts. As far as I know, all existing drivers currently do this. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Reported-and-tested-by: syzbot+7634edaea4d0b341c625@syzkaller.appspotmail.com CC: <stable@vger.kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--Documentation/driver-api/usb/power-management.rst14
-rw-r--r--drivers/usb/core/driver.c13
-rw-r--r--drivers/usb/storage/realtek_cr.c13
-rw-r--r--include/linux/usb.h2
4 files changed, 14 insertions, 28 deletions
diff --git a/Documentation/driver-api/usb/power-management.rst b/Documentation/driver-api/usb/power-management.rst
index 79beb807996b..4a74cf6f2797 100644
--- a/Documentation/driver-api/usb/power-management.rst
+++ b/Documentation/driver-api/usb/power-management.rst
@@ -370,11 +370,15 @@ autosuspend the interface's device. When the usage counter is = 0
370then the interface is considered to be idle, and the kernel may 370then the interface is considered to be idle, and the kernel may
371autosuspend the device. 371autosuspend the device.
372 372
373Drivers need not be concerned about balancing changes to the usage 373Drivers must be careful to balance their overall changes to the usage
374counter; the USB core will undo any remaining "get"s when a driver 374counter. Unbalanced "get"s will remain in effect when a driver is
375is unbound from its interface. As a corollary, drivers must not call 375unbound from its interface, preventing the device from going into
376any of the ``usb_autopm_*`` functions after their ``disconnect`` 376runtime suspend should the interface be bound to a driver again. On
377routine has returned. 377the other hand, drivers are allowed to achieve this balance by calling
378the ``usb_autopm_*`` functions even after their ``disconnect`` routine
379has returned -- say from within a work-queue routine -- provided they
380retain an active reference to the interface (via ``usb_get_intf`` and
381``usb_put_intf``).
378 382
379Drivers using the async routines are responsible for their own 383Drivers using the async routines are responsible for their own
380synchronization and mutual exclusion. 384synchronization and mutual exclusion.
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index 8987cec9549d..ebcadaad89d1 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -473,11 +473,6 @@ static int usb_unbind_interface(struct device *dev)
473 pm_runtime_disable(dev); 473 pm_runtime_disable(dev);
474 pm_runtime_set_suspended(dev); 474 pm_runtime_set_suspended(dev);
475 475
476 /* Undo any residual pm_autopm_get_interface_* calls */
477 for (r = atomic_read(&intf->pm_usage_cnt); r > 0; --r)
478 usb_autopm_put_interface_no_suspend(intf);
479 atomic_set(&intf->pm_usage_cnt, 0);
480
481 if (!error) 476 if (!error)
482 usb_autosuspend_device(udev); 477 usb_autosuspend_device(udev);
483 478
@@ -1633,7 +1628,6 @@ void usb_autopm_put_interface(struct usb_interface *intf)
1633 int status; 1628 int status;
1634 1629
1635 usb_mark_last_busy(udev); 1630 usb_mark_last_busy(udev);
1636 atomic_dec(&intf->pm_usage_cnt);
1637 status = pm_runtime_put_sync(&intf->dev); 1631 status = pm_runtime_put_sync(&intf->dev);
1638 dev_vdbg(&intf->dev, "%s: cnt %d -> %d\n", 1632 dev_vdbg(&intf->dev, "%s: cnt %d -> %d\n",
1639 __func__, atomic_read(&intf->dev.power.usage_count), 1633 __func__, atomic_read(&intf->dev.power.usage_count),
@@ -1662,7 +1656,6 @@ void usb_autopm_put_interface_async(struct usb_interface *intf)
1662 int status; 1656 int status;
1663 1657
1664 usb_mark_last_busy(udev); 1658 usb_mark_last_busy(udev);
1665 atomic_dec(&intf->pm_usage_cnt);
1666 status = pm_runtime_put(&intf->dev); 1659 status = pm_runtime_put(&intf->dev);
1667 dev_vdbg(&intf->dev, "%s: cnt %d -> %d\n", 1660 dev_vdbg(&intf->dev, "%s: cnt %d -> %d\n",
1668 __func__, atomic_read(&intf->dev.power.usage_count), 1661 __func__, atomic_read(&intf->dev.power.usage_count),
@@ -1684,7 +1677,6 @@ void usb_autopm_put_interface_no_suspend(struct usb_interface *intf)
1684 struct usb_device *udev = interface_to_usbdev(intf); 1677 struct usb_device *udev = interface_to_usbdev(intf);
1685 1678
1686 usb_mark_last_busy(udev); 1679 usb_mark_last_busy(udev);
1687 atomic_dec(&intf->pm_usage_cnt);
1688 pm_runtime_put_noidle(&intf->dev); 1680 pm_runtime_put_noidle(&intf->dev);
1689} 1681}
1690EXPORT_SYMBOL_GPL(usb_autopm_put_interface_no_suspend); 1682EXPORT_SYMBOL_GPL(usb_autopm_put_interface_no_suspend);
@@ -1715,8 +1707,6 @@ int usb_autopm_get_interface(struct usb_interface *intf)
1715 status = pm_runtime_get_sync(&intf->dev); 1707 status = pm_runtime_get_sync(&intf->dev);
1716 if (status < 0) 1708 if (status < 0)
1717 pm_runtime_put_sync(&intf->dev); 1709 pm_runtime_put_sync(&intf->dev);
1718 else
1719 atomic_inc(&intf->pm_usage_cnt);
1720 dev_vdbg(&intf->dev, "%s: cnt %d -> %d\n", 1710 dev_vdbg(&intf->dev, "%s: cnt %d -> %d\n",
1721 __func__, atomic_read(&intf->dev.power.usage_count), 1711 __func__, atomic_read(&intf->dev.power.usage_count),
1722 status); 1712 status);
@@ -1750,8 +1740,6 @@ int usb_autopm_get_interface_async(struct usb_interface *intf)
1750 status = pm_runtime_get(&intf->dev); 1740 status = pm_runtime_get(&intf->dev);
1751 if (status < 0 && status != -EINPROGRESS) 1741 if (status < 0 && status != -EINPROGRESS)
1752 pm_runtime_put_noidle(&intf->dev); 1742 pm_runtime_put_noidle(&intf->dev);
1753 else
1754 atomic_inc(&intf->pm_usage_cnt);
1755 dev_vdbg(&intf->dev, "%s: cnt %d -> %d\n", 1743 dev_vdbg(&intf->dev, "%s: cnt %d -> %d\n",
1756 __func__, atomic_read(&intf->dev.power.usage_count), 1744 __func__, atomic_read(&intf->dev.power.usage_count),
1757 status); 1745 status);
@@ -1775,7 +1763,6 @@ void usb_autopm_get_interface_no_resume(struct usb_interface *intf)
1775 struct usb_device *udev = interface_to_usbdev(intf); 1763 struct usb_device *udev = interface_to_usbdev(intf);
1776 1764
1777 usb_mark_last_busy(udev); 1765 usb_mark_last_busy(udev);
1778 atomic_inc(&intf->pm_usage_cnt);
1779 pm_runtime_get_noresume(&intf->dev); 1766 pm_runtime_get_noresume(&intf->dev);
1780} 1767}
1781EXPORT_SYMBOL_GPL(usb_autopm_get_interface_no_resume); 1768EXPORT_SYMBOL_GPL(usb_autopm_get_interface_no_resume);
diff --git a/drivers/usb/storage/realtek_cr.c b/drivers/usb/storage/realtek_cr.c
index 31b024441938..cc794e25a0b6 100644
--- a/drivers/usb/storage/realtek_cr.c
+++ b/drivers/usb/storage/realtek_cr.c
@@ -763,18 +763,16 @@ static void rts51x_suspend_timer_fn(struct timer_list *t)
763 break; 763 break;
764 case RTS51X_STAT_IDLE: 764 case RTS51X_STAT_IDLE:
765 case RTS51X_STAT_SS: 765 case RTS51X_STAT_SS:
766 usb_stor_dbg(us, "RTS51X_STAT_SS, intf->pm_usage_cnt:%d, power.usage:%d\n", 766 usb_stor_dbg(us, "RTS51X_STAT_SS, power.usage:%d\n",
767 atomic_read(&us->pusb_intf->pm_usage_cnt),
768 atomic_read(&us->pusb_intf->dev.power.usage_count)); 767 atomic_read(&us->pusb_intf->dev.power.usage_count));
769 768
770 if (atomic_read(&us->pusb_intf->pm_usage_cnt) > 0) { 769 if (atomic_read(&us->pusb_intf->dev.power.usage_count) > 0) {
771 usb_stor_dbg(us, "Ready to enter SS state\n"); 770 usb_stor_dbg(us, "Ready to enter SS state\n");
772 rts51x_set_stat(chip, RTS51X_STAT_SS); 771 rts51x_set_stat(chip, RTS51X_STAT_SS);
773 /* ignore mass storage interface's children */ 772 /* ignore mass storage interface's children */
774 pm_suspend_ignore_children(&us->pusb_intf->dev, true); 773 pm_suspend_ignore_children(&us->pusb_intf->dev, true);
775 usb_autopm_put_interface_async(us->pusb_intf); 774 usb_autopm_put_interface_async(us->pusb_intf);
776 usb_stor_dbg(us, "RTS51X_STAT_SS 01, intf->pm_usage_cnt:%d, power.usage:%d\n", 775 usb_stor_dbg(us, "RTS51X_STAT_SS 01, power.usage:%d\n",
777 atomic_read(&us->pusb_intf->pm_usage_cnt),
778 atomic_read(&us->pusb_intf->dev.power.usage_count)); 776 atomic_read(&us->pusb_intf->dev.power.usage_count));
779 } 777 }
780 break; 778 break;
@@ -807,11 +805,10 @@ static void rts51x_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
807 int ret; 805 int ret;
808 806
809 if (working_scsi(srb)) { 807 if (working_scsi(srb)) {
810 usb_stor_dbg(us, "working scsi, intf->pm_usage_cnt:%d, power.usage:%d\n", 808 usb_stor_dbg(us, "working scsi, power.usage:%d\n",
811 atomic_read(&us->pusb_intf->pm_usage_cnt),
812 atomic_read(&us->pusb_intf->dev.power.usage_count)); 809 atomic_read(&us->pusb_intf->dev.power.usage_count));
813 810
814 if (atomic_read(&us->pusb_intf->pm_usage_cnt) <= 0) { 811 if (atomic_read(&us->pusb_intf->dev.power.usage_count) <= 0) {
815 ret = usb_autopm_get_interface(us->pusb_intf); 812 ret = usb_autopm_get_interface(us->pusb_intf);
816 usb_stor_dbg(us, "working scsi, ret=%d\n", ret); 813 usb_stor_dbg(us, "working scsi, ret=%d\n", ret);
817 } 814 }
diff --git a/include/linux/usb.h b/include/linux/usb.h
index 5e49e82c4368..ff010d1fd1c7 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -200,7 +200,6 @@ usb_find_last_int_out_endpoint(struct usb_host_interface *alt,
200 * @dev: driver model's view of this device 200 * @dev: driver model's view of this device
201 * @usb_dev: if an interface is bound to the USB major, this will point 201 * @usb_dev: if an interface is bound to the USB major, this will point
202 * to the sysfs representation for that device. 202 * to the sysfs representation for that device.
203 * @pm_usage_cnt: PM usage counter for this interface
204 * @reset_ws: Used for scheduling resets from atomic context. 203 * @reset_ws: Used for scheduling resets from atomic context.
205 * @resetting_device: USB core reset the device, so use alt setting 0 as 204 * @resetting_device: USB core reset the device, so use alt setting 0 as
206 * current; needs bandwidth alloc after reset. 205 * current; needs bandwidth alloc after reset.
@@ -257,7 +256,6 @@ struct usb_interface {
257 256
258 struct device dev; /* interface specific device info */ 257 struct device dev; /* interface specific device info */
259 struct device *usb_dev; 258 struct device *usb_dev;
260 atomic_t pm_usage_cnt; /* usage counter for autosuspend */
261 struct work_struct reset_ws; /* for resets in atomic context */ 259 struct work_struct reset_ws; /* for resets in atomic context */
262}; 260};
263#define to_usb_interface(d) container_of(d, struct usb_interface, dev) 261#define to_usb_interface(d) container_of(d, struct usb_interface, dev)