diff options
author | Jiri Kosina <jkosina@suse.cz> | 2010-08-13 06:19:45 -0400 |
---|---|---|
committer | Jiri Kosina <jkosina@suse.cz> | 2010-08-13 06:19:45 -0400 |
commit | 9c9e54a8df0be48aa359744f412377cc55c3b7d2 (patch) | |
tree | 1df6c9dde015a961c2841437cb757e36119e7ea6 /drivers/hid | |
parent | 7032269e87ade34cc12891675371fa2ac150a620 (diff) |
HID: hiddev: fix memory corruption due to invalid intfdata
Commit bd25f4dd6972755579d0 ("HID: hiddev: use usb_find_interface,
get rid of BKL") introduced using of private intfdata in hiddev for
purpose of storing hiddev pointer.
This is a problem, because intf pointer is already being set to struct
hid_device pointer by HID core. This obviously lead to memory corruptions
at device disconnect time, such as
WARNING: at lib/kobject.c:595 kobject_put+0x37/0x4b()
kobject: '(null)' (ffff88011e9cd898): is not initialized, yet kobject_put() is being called.
Convert hiddev into accessing hiddev through struct hid_device which is
in intfdata already.
Reported-and-tested-by: Markus Trippelsdorf <markus@trippelsdorf.de>
Reported-and-tested-by: Heinz Diehl <htd@fritha.org>
Reported-and-tested-by: Alan Ott <alan@signal11.us>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'drivers/hid')
-rw-r--r-- | drivers/hid/usbhid/hiddev.c | 5 |
1 files changed, 3 insertions, 2 deletions
diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c index f2850171a69b..0a29c51114aa 100644 --- a/drivers/hid/usbhid/hiddev.c +++ b/drivers/hid/usbhid/hiddev.c | |||
@@ -266,13 +266,15 @@ static int hiddev_open(struct inode *inode, struct file *file) | |||
266 | { | 266 | { |
267 | struct hiddev_list *list; | 267 | struct hiddev_list *list; |
268 | struct usb_interface *intf; | 268 | struct usb_interface *intf; |
269 | struct hid_device *hid; | ||
269 | struct hiddev *hiddev; | 270 | struct hiddev *hiddev; |
270 | int res; | 271 | int res; |
271 | 272 | ||
272 | intf = usb_find_interface(&hiddev_driver, iminor(inode)); | 273 | intf = usb_find_interface(&hiddev_driver, iminor(inode)); |
273 | if (!intf) | 274 | if (!intf) |
274 | return -ENODEV; | 275 | return -ENODEV; |
275 | hiddev = usb_get_intfdata(intf); | 276 | hid = usb_get_intfdata(intf); |
277 | hiddev = hid->hiddev; | ||
276 | 278 | ||
277 | if (!(list = kzalloc(sizeof(struct hiddev_list), GFP_KERNEL))) | 279 | if (!(list = kzalloc(sizeof(struct hiddev_list), GFP_KERNEL))) |
278 | return -ENOMEM; | 280 | return -ENOMEM; |
@@ -890,7 +892,6 @@ int hiddev_connect(struct hid_device *hid, unsigned int force) | |||
890 | hid->hiddev = hiddev; | 892 | hid->hiddev = hiddev; |
891 | hiddev->hid = hid; | 893 | hiddev->hid = hid; |
892 | hiddev->exist = 1; | 894 | hiddev->exist = 1; |
893 | usb_set_intfdata(usbhid->intf, usbhid); | ||
894 | retval = usb_register_dev(usbhid->intf, &hiddev_class); | 895 | retval = usb_register_dev(usbhid->intf, &hiddev_class); |
895 | if (retval) { | 896 | if (retval) { |
896 | err_hid("Not able to get a minor for this device."); | 897 | err_hid("Not able to get a minor for this device."); |