Commit 2259a939 authored by Tasos Sahanidis's avatar Tasos Sahanidis Committed by Peng Zhang
Browse files

usb: core: Don't hold the device lock while sleeping in do_proc_control()

mainline inclusion
from mainline-v5.18-rc5
commit 0543e4e8
category: bugfix
bugzilla: https://gitee.com/src-openeuler/kernel/issues/IA6SH6
CVE: CVE-2021-47582

Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=0543e4e8852ef5ff1809ae62f1ea963e2ab23b66



--------------------------------

Since commit ae8709b2 ("USB: core: Make do_proc_control() and
do_proc_bulk() killable") if a device has the USB_QUIRK_DELAY_CTRL_MSG
quirk set, it will temporarily block all other URBs (e.g. interrupts)
while sleeping due to a control.

This results in noticeable delays when, for example, a userspace usbfs
application is sending URB interrupts at a high rate to a keyboard and
simultaneously updates the lock indicators using controls. Interrupts
with direction set to IN are also affected by this, meaning that
delivery of HID reports (containing scancodes) to the usbfs application
is delayed as well.

This patch fixes the regression by calling msleep() while the device
mutex is unlocked, as was the case originally with usb_control_msg().

Fixes: ae8709b2 ("USB: core: Make do_proc_control() and do_proc_bulk() killable")
Cc: stable <stable@kernel.org>
Acked-by: default avatarAlan Stern <stern@rowland.harvard.edu>
Signed-off-by: default avatarTasos Sahanidis <tasos@tasossah.com>
Link: https://lore.kernel.org/r/3e299e2a-13b9-ddff-7fee-6845e868bc06@tasossah.com


Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: default avatarZhangPeng <zhangpeng362@huawei.com>
parent 0abc1f1b
Loading
Loading
Loading
Loading
+9 −5
Original line number Diff line number Diff line
@@ -1207,12 +1207,16 @@ static int do_proc_control(struct usb_dev_state *ps,

		usb_unlock_device(dev);
		i = usbfs_start_wait_urb(urb, tmo, &actlen);

		/* Linger a bit, prior to the next control message. */
		if (dev->quirks & USB_QUIRK_DELAY_CTRL_MSG)
			msleep(200);
		usb_lock_device(dev);
		snoop_urb(dev, NULL, pipe, actlen, i, COMPLETE, tbuf, actlen);
		if (!i && actlen) {
			if (copy_to_user(ctrl->data, tbuf, actlen)) {
				ret = -EFAULT;
				goto recv_fault;
				goto done;
			}
		}
	} else {
@@ -1229,6 +1233,10 @@ static int do_proc_control(struct usb_dev_state *ps,

		usb_unlock_device(dev);
		i = usbfs_start_wait_urb(urb, tmo, &actlen);

		/* Linger a bit, prior to the next control message. */
		if (dev->quirks & USB_QUIRK_DELAY_CTRL_MSG)
			msleep(200);
		usb_lock_device(dev);
		snoop_urb(dev, NULL, pipe, actlen, i, COMPLETE, NULL, 0);
	}
@@ -1240,10 +1248,6 @@ static int do_proc_control(struct usb_dev_state *ps,
	}
	ret = (i < 0 ? i : actlen);

 recv_fault:
	/* Linger a bit, prior to the next control message. */
	if (dev->quirks & USB_QUIRK_DELAY_CTRL_MSG)
		msleep(200);
 done:
	kfree(dr);
	usb_free_urb(urb);