| From f7744fa16b96da57187dc8e5634152d3b63d72de Mon Sep 17 00:00:00 2001 |
| From: Anirudh Rayabharam <mail@anirudhrb.com> |
| Date: Thu, 24 Jun 2021 00:10:29 +0530 |
| Subject: HID: usbhid: free raw_report buffers in usbhid_stop |
| |
| From: Anirudh Rayabharam <mail@anirudhrb.com> |
| |
| commit f7744fa16b96da57187dc8e5634152d3b63d72de upstream. |
| |
| Free the unsent raw_report buffers when the device is removed. |
| |
| Fixes a memory leak reported by syzbot at: |
| https://syzkaller.appspot.com/bug?id=7b4fa7cb1a7c2d3342a2a8a6c53371c8c418ab47 |
| |
| Reported-by: syzbot+47b26cd837ececfc666d@syzkaller.appspotmail.com |
| Tested-by: syzbot+47b26cd837ececfc666d@syzkaller.appspotmail.com |
| Signed-off-by: Anirudh Rayabharam <mail@anirudhrb.com> |
| Signed-off-by: Jiri Kosina <jkosina@suse.cz> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| drivers/hid/usbhid/hid-core.c | 13 ++++++++++++- |
| 1 file changed, 12 insertions(+), 1 deletion(-) |
| |
| --- a/drivers/hid/usbhid/hid-core.c |
| +++ b/drivers/hid/usbhid/hid-core.c |
| @@ -503,7 +503,7 @@ static void hid_ctrl(struct urb *urb) |
| |
| if (unplug) { |
| usbhid->ctrltail = usbhid->ctrlhead; |
| - } else { |
| + } else if (usbhid->ctrlhead != usbhid->ctrltail) { |
| usbhid->ctrltail = (usbhid->ctrltail + 1) & (HID_CONTROL_FIFO_SIZE - 1); |
| |
| if (usbhid->ctrlhead != usbhid->ctrltail && |
| @@ -1221,9 +1221,20 @@ static void usbhid_stop(struct hid_devic |
| mutex_lock(&usbhid->mutex); |
| |
| clear_bit(HID_STARTED, &usbhid->iofl); |
| + |
| spin_lock_irq(&usbhid->lock); /* Sync with error and led handlers */ |
| set_bit(HID_DISCONNECTED, &usbhid->iofl); |
| + while (usbhid->ctrltail != usbhid->ctrlhead) { |
| + if (usbhid->ctrl[usbhid->ctrltail].dir == USB_DIR_OUT) { |
| + kfree(usbhid->ctrl[usbhid->ctrltail].raw_report); |
| + usbhid->ctrl[usbhid->ctrltail].raw_report = NULL; |
| + } |
| + |
| + usbhid->ctrltail = (usbhid->ctrltail + 1) & |
| + (HID_CONTROL_FIFO_SIZE - 1); |
| + } |
| spin_unlock_irq(&usbhid->lock); |
| + |
| usb_kill_urb(usbhid->urbin); |
| usb_kill_urb(usbhid->urbout); |
| usb_kill_urb(usbhid->urbctrl); |