Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 54d2bc06 authored by Oliver Neukum's avatar Oliver Neukum Committed by Greg Kroah-Hartman
Browse files

USB: fix locking in idmouse



Pete caused me to lock at buggy drivers in this respect. The idmouse has
a race between open and disconnect. This patch

- solves the open/disconnect race
- switches locking to mutexes

Signed-off-by: default avatarOliver Neukum <oneukum@suse.de>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 439a903a
Loading
Loading
Loading
Loading
+28 −17
Original line number Original line Diff line number Diff line
@@ -66,6 +66,7 @@ static struct usb_device_id idmouse_table[] = {
	USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT, value, index, NULL, 0, 1000)
	USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT, value, index, NULL, 0, 1000)


MODULE_DEVICE_TABLE(usb, idmouse_table);
MODULE_DEVICE_TABLE(usb, idmouse_table);
static DEFINE_MUTEX(open_disc_mutex);


/* structure to hold all of our device specific stuff */
/* structure to hold all of our device specific stuff */
struct usb_idmouse {
struct usb_idmouse {
@@ -80,7 +81,7 @@ struct usb_idmouse {


	int open; /* if the port is open or not */
	int open; /* if the port is open or not */
	int present; /* if the device is not disconnected */
	int present; /* if the device is not disconnected */
	struct semaphore sem; /* locks this structure */
	struct mutex lock; /* locks this structure */


};
};


@@ -213,13 +214,17 @@ static int idmouse_open(struct inode *inode, struct file *file)
	if (!interface)
	if (!interface)
		return -ENODEV;
		return -ENODEV;


	mutex_lock(&open_disc_mutex);
	/* get the device information block from the interface */
	/* get the device information block from the interface */
	dev = usb_get_intfdata(interface);
	dev = usb_get_intfdata(interface);
	if (!dev)
	if (!dev) {
		mutex_unlock(&open_disc_mutex);
		return -ENODEV;
		return -ENODEV;
	}


	/* lock this device */
	/* lock this device */
	down(&dev->sem);
	mutex_lock(&dev->lock);
	mutex_unlock(&open_disc_mutex);


	/* check if already open */
	/* check if already open */
	if (dev->open) {
	if (dev->open) {
@@ -245,7 +250,7 @@ static int idmouse_open(struct inode *inode, struct file *file)
error:
error:


	/* unlock this device */
	/* unlock this device */
	up(&dev->sem);
	mutex_unlock(&dev->lock);
	return result;
	return result;
}
}


@@ -258,12 +263,14 @@ static int idmouse_release(struct inode *inode, struct file *file)
	if (dev == NULL)
	if (dev == NULL)
		return -ENODEV;
		return -ENODEV;


	mutex_lock(&open_disc_mutex);
	/* lock our device */
	/* lock our device */
	down(&dev->sem);
	mutex_lock(&dev->lock);


	/* are we really open? */
	/* are we really open? */
	if (dev->open <= 0) {
	if (dev->open <= 0) {
		up(&dev->sem);
		mutex_unlock(&dev->lock);
		mutex_unlock(&open_disc_mutex);
		return -ENODEV;
		return -ENODEV;
	}
	}


@@ -271,10 +278,12 @@ static int idmouse_release(struct inode *inode, struct file *file)


	if (!dev->present) {
	if (!dev->present) {
		/* the device was unplugged before the file was released */
		/* the device was unplugged before the file was released */
		up(&dev->sem);
		mutex_unlock(&dev->lock);
		mutex_unlock(&open_disc_mutex);
		idmouse_delete(dev);
		idmouse_delete(dev);
	} else {
	} else {
		up(&dev->sem);
		mutex_unlock(&dev->lock);
		mutex_unlock(&open_disc_mutex);
	}
	}
	return 0;
	return 0;
}
}
@@ -286,18 +295,18 @@ static ssize_t idmouse_read(struct file *file, char __user *buffer, size_t count
	int result;
	int result;


	/* lock this object */
	/* lock this object */
	down(&dev->sem);
	mutex_lock(&dev->lock);


	/* verify that the device wasn't unplugged */
	/* verify that the device wasn't unplugged */
	if (!dev->present) {
	if (!dev->present) {
		up(&dev->sem);
		mutex_unlock(&dev->lock);
		return -ENODEV;
		return -ENODEV;
	}
	}


	result = simple_read_from_buffer(buffer, count, ppos,
	result = simple_read_from_buffer(buffer, count, ppos,
					dev->bulk_in_buffer, IMGSIZE);
					dev->bulk_in_buffer, IMGSIZE);
	/* unlock the device */
	/* unlock the device */
	up(&dev->sem);
	mutex_unlock(&dev->lock);
	return result;
	return result;
}
}


@@ -320,7 +329,7 @@ static int idmouse_probe(struct usb_interface *interface,
	if (dev == NULL)
	if (dev == NULL)
		return -ENOMEM;
		return -ENOMEM;


	init_MUTEX(&dev->sem);
	mutex_init(&dev->lock);
	dev->udev = udev;
	dev->udev = udev;
	dev->interface = interface;
	dev->interface = interface;


@@ -372,24 +381,26 @@ static void idmouse_disconnect(struct usb_interface *interface)


	/* get device structure */
	/* get device structure */
	dev = usb_get_intfdata(interface);
	dev = usb_get_intfdata(interface);
	usb_set_intfdata(interface, NULL);


	/* give back our minor */
	/* give back our minor */
	usb_deregister_dev(interface, &idmouse_class);
	usb_deregister_dev(interface, &idmouse_class);


	/* lock it */
	mutex_lock(&open_disc_mutex);
	down(&dev->sem);
	usb_set_intfdata(interface, NULL);
	/* lock the device */
	mutex_lock(&dev->lock);
	mutex_unlock(&open_disc_mutex);


	/* prevent device read, write and ioctl */
	/* prevent device read, write and ioctl */
	dev->present = 0;
	dev->present = 0;


	/* if the device is opened, idmouse_release will clean this up */
	/* if the device is opened, idmouse_release will clean this up */
	if (!dev->open) {
	if (!dev->open) {
		up(&dev->sem);
		mutex_unlock(&dev->lock);
		idmouse_delete(dev);
		idmouse_delete(dev);
	} else {
	} else {
		/* unlock */
		/* unlock */
		up(&dev->sem);
		mutex_unlock(&dev->lock);
	}
	}


	info("%s disconnected", DRIVER_DESC);
	info("%s disconnected", DRIVER_DESC);