HID: usbhid: fix asynchronous resource free
authorHans Yang <hansy@nvidia.com>
Tue, 8 Nov 2016 09:31:25 +0000 (17:31 +0800)
committermobile promotions <svcmobile_promotions@nvidia.com>
Thu, 10 Nov 2016 17:00:16 +0000 (09:00 -0800)
commit6729526e2a813daa6cbed2a2983e6a585bb2c960
tree35c8a0e655fbba45aa4515e03a4ec9b9acf4e689
parentd10ae6eb4218bcdb2ae383f054f18a8b90d52c7b
HID: usbhid: fix asynchronous resource free

If usb_disconnect() and usbhid_disconnect() are invoked
asynchronously due to bottom-half workqueue to postpone
work in usbhid_disconnect(), following conditions might
occur:
* struct usb_device *dev memory resource has been freed.
* struct hid_device *dev is still available.
* user space issues a write to get hid report, calling
usbhid_output_raw_report() and lead to a kernel panic
due to invalid dereference from usbhid_device* to usb_dev*.

[ 137.137063] Unable to handle kernel paging request at
virtual address 000010ef
[ 137.144426] pgd = ffffffc0a1ec2000
[ 138.488914] Call trace:
[ 138.491362] [<ffffffc00073d0fc>] usb_submit_urb+0xb4/0x3e4
[ 138.496842] [<ffffffc00073e0f8>] usb_start_wait_urb+0x54/0x130
[ 138.502667] [<ffffffc00073e280>] usb_control_msg+0xac/0xf4
[ 138.508147] [<ffffffc000941aa8>] usbhid_output_raw_report+0xb8/0x10c
[ 138.514494] [<ffffffc00091ab0c>] hidraw_send_report+0x134/0x168
[ 138.520407] [<ffffffc00091ab7c>] hidraw_write+0x3c/0x58
[ 138.525625] [<ffffffc0001a1280>] vfs_write+0xc0/0x17c
[ 138.530669] [<ffffffc0001a1abc>] SyS_write+0x94/0x164

Also, if usb_dev memory is freed before freeing usbhid_device
resources, following crash dump may also be seen:

[42230.701858] Call trace:
[42230.704306] [<ffffffc000724e64>] hcd_buffer_free+0x18/0x130
[42230.709872] [<ffffffc000712a28>] usb_free_coherent+0x1c/0x24
[42230.715526] [<ffffffc000917ad8>] hid_free_buffers.isra.7+0x24/0x60
[42230.721696] [<ffffffc000917bf8>] usbhid_stop+0xe4/0x108
[42230.726914] [<ffffffc000913a80>] atvr_remove+0xa4/0x138
[42230.732134] [<ffffffc0008ec5f4>] hid_device_remove+0x80/0xc4
[42230.737788] [<ffffffc00051f7bc>] __device_release_driver+0x94/0xe4
[42230.743961] [<ffffffc00051f830>] device_release_driver+0x24/0x38
[42230.749959] [<ffffffc00051efd0>] bus_remove_device+0x140/0x164
[42230.755782] [<ffffffc00051c43c>] device_del+0x13c/0x19c
[42230.761001] [<ffffffc0008ec76c>] hid_destroy_device+0x28/0x60
[42230.766738] [<ffffffc000916b08>] usbhid_disconnect_bh+0x28/0x3c
[42230.772652] [<ffffffc0000c9a6c>] process_one_work+0x260/0x410
[42230.778390] [<ffffffc0000cabac>] worker_thread+0x204/0x378
[42230.783870] [<ffffffc0000d12a0>] kthread+0xc0/0xc8

This commit forces the usbhid_device and usb_dev resources
free are in order by introducing reference couning method into
usb hid driver. Whatever usb_disconnect() or usbhid_stop() is called
first, the usb_dev memory will only be freed when ref count goes to
zero, just before usbhid_device memory gets freed.

Bug 1834364

Signed-off-by: Hans Yang <hansy@nvidia.com>
Change-Id: I81748c60216c81dae55daaa9b0f331152121f8f6
Reviewed-on: http://git-master/r/1249662
Reviewed-by: Spencer Sutterlin <ssutterlin@nvidia.com>
Tested-by: Spencer Sutterlin <ssutterlin@nvidia.com>
Reviewed-by: Henry Lin <henryl@nvidia.com>
GVS: Gerrit_Virtual_Submit
Reviewed-by: ChihMin Cheng <ccheng@nvidia.com>
Reviewed-by: Vinayak Pane <vpane@nvidia.com>
drivers/hid/usbhid/hid-core.c