Potential trouble in usbhid

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi all,

We've experienced some issues with an application that uses hiddev devices. This application regularly performs ioctl syscalls on a hiddev device (/dev/usb/hiddev0) with the intent to get report information. This works fine, until the device is physically disconnected. 

For context, here's a snippet from drivers/hid/usb/hiddev.c:

-------
static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
	struct hiddev_list *list = file->private_data;
	struct hiddev *hiddev = list->hiddev;
	struct hid_device *hid = hiddev->hid;
	struct usb_device *dev = hid_to_usb_dev(hid);
	struct hiddev_collection_info cinfo;
	struct hiddev_report_info rinfo;
	struct hiddev_field_info finfo;
	struct hiddev_devinfo dinfo;
	struct hid_report *report;
	struct hid_field *field;
	struct usbhid_device *usbhid = hid->driver_data;
	void __user *user_arg = (void __user *)arg;
	int i, r;
	
	/* Called without BKL by compat methods so no BKL taken */

	/* FIXME: Who or what stop this racing with a disconnect ?? */
	if (!hiddev->exist)
		return -EIO;
-------

We found that in rare circumstances, the deference in the third line fails, i.e. list->hiddev does not hold a valid pointer. Here's the trace from the kernel:

Jan 13 10:32:31 ehv-nb-001 kernel: [ 7525.637584] EIP: 0060:[<f80d4d7c>] EFLAGS: 00010292 CPU: 0
Jan 13 10:32:31 ehv-nb-001 kernel: [ 7525.637596] EIP is at hiddev_ioctl+0x2c/0x680 [usbhid]
Jan 13 10:32:31 ehv-nb-001 kernel: [ 7525.637601] EAX: 00000000 EBX: ee538000 ECX: bf8d78a8 EDX: 4018480c
Jan 13 10:32:31 ehv-nb-001 kernel: [ 7525.637607] ESI: ee24dd80 EDI: f08e0000 EBP: f5663f50 ESP: f5663ec8
Jan 13 10:32:31 ehv-nb-001 kernel: [ 7525.637612]  DS: 007b ES: 007b FS: 00d8 GS: 00e0 SS: 0068
Jan 13 10:32:31 ehv-nb-001 kernel: [ 7525.637627]  00000000 f5663ed8 bf8d78a8 00000000 00000001 ffffffff f3b64300 00000000
Jan 13 10:32:31 ehv-nb-001 kernel: [ 7525.637641] <0> 00000000 00000000 00000000 f6bd9980 00000000 00000000 00000000 f6bd9980
Jan 13 10:32:31 ehv-nb-001 kernel: [ 7525.637657] <0> c0167b50 f5663f0c f5663f0c 00000000 00000000 f5663e70 f5663f28 c03bb5dd
Jan 13 10:32:31 ehv-nb-001 kernel: [ 7525.637687]  [<c0167b50>] ? autoremove_wake_function+0x0/0x50
Jan 13 10:32:31 ehv-nb-001 kernel: [ 7525.637697]  [<c03bb5dd>] ? tty_ldisc_deref+0xd/0x10
Jan 13 10:32:31 ehv-nb-001 kernel: [ 7525.637707]  [<c02f5c14>] ? security_file_permission+0x14/0x20
Jan 13 10:32:31 ehv-nb-001 kernel: [ 7525.637717]  [<c0208a24>] ? rw_verify_area+0x64/0xe0
Jan 13 10:32:31 ehv-nb-001 kernel: [ 7525.637743]  [<f80d4d50>] ? hiddev_ioctl+0x0/0x680 [usbhid]
Jan 13 10:32:31 ehv-nb-001 kernel: [ 7525.637756]  [<c0217211>] ? vfs_ioctl+0x21/0x90
Jan 13 10:32:31 ehv-nb-001 kernel: [ 7525.637764]  [<c0171b96>] ? getnstimeofday+0x56/0x110
Jan 13 10:32:31 ehv-nb-001 kernel: [ 7525.637771]  [<c02174f9>] ? do_vfs_ioctl+0x79/0x310
Jan 13 10:32:31 ehv-nb-001 kernel: [ 7525.637779]  [<c03549a9>] ? copy_to_user+0x39/0x130
Jan 13 10:32:31 ehv-nb-001 kernel: [ 7525.637786]  [<c02177f7>] ? sys_ioctl+0x67/0x80
Jan 13 10:32:31 ehv-nb-001 kernel: [ 7525.637794]  [<c01033ec>] ? syscall_call+0x7/0xb
Jan 13 10:32:31 ehv-nb-001 kernel: [ 7525.638001] ---[ end trace beb5a9ffee100cae ]---

hiddev_ioctl+0x2c is a dereference of EAX, which is 00000000. 

It seems to be a problem related to the 'unbinding' of hiddev from the list, resulting in list->hiddev being 0, while 'file' still refers to a valid file. We suspect that the 'FIXME' mentioned is also related, except that in our case sometimes the 'hiddev' is gone.

We've patched these lines:

------
static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
	struct hiddev_list *list = file->private_data;
	struct hiddev *hiddev = list->hiddev;
	struct hid_device *hid;
	struct usb_device *dev;
	struct hiddev_collection_info cinfo;
	struct hiddev_report_info rinfo;
	struct hiddev_field_info finfo;
	struct hiddev_devinfo dinfo;
	struct hid_report *report;
	struct hid_field *field;
	struct usbhid_device *usbhid;
	void __user *user_arg;
	int i, r;

	if (hiddev == NULL)
		return -EIO;
	
	hid = hiddev->hid;

	if (hid == NULL || &(hid->dev) == NULL ||
	    hid->dev.parent == NULL)
		return -EIO;

	dev = hid_to_usb_dev(hid);

	usbhid = hid->driver_data;
	user_arg = (void __user *)arg;
------

This seems to be enough to solve the symptom. Not sure whether the same caution should be applied to the dereferencing of
'list', or even 'file' for that matter.

Regards,

Robert Lukassen




This e-mail message contains information which is confidential and may be privileged. It is intended for use by the addressee only. If you are not the intended addressee, we request that you notify the sender immediately and delete or destroy this e-mail message and any attachment(s), without copying, saving, forwarding, disclosing or using its contents in any other way. TomTom N.V., TomTom International BV or any other company belonging to the TomTom group of companies will not be liable for damage relating to the communication by e-mail of data, documents or any other information.
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux