USB: adutux: fix use-after-free on disconnect
Subsystems (2)
PATCH 1/2 USB: adutux: fix use-after-free on disconnect
The driver was clearing its struct usb_device pointer, which it used as an inverted disconnected flag, before deregistering the character device and without serialising against racing release().
This could lead to a use-after-free if a racing release() callback observes the cleared pointer and frees the driver data before disconnect() is finished with it.
This could also lead to NULL-pointer dereferences in a racing open().
--- drivers/usb/misc/adutux.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
drivers/usb/misc/adutux.c +4 -3
@@ -762,14 +762,15 @@ static void adu_disconnect(struct usb_interface *interface) dev =usb_get_intfdata (interface); -mutex_lock (&dev->mtx);/* not interruptible */ - dev->udev =NULL ;/* poison */ usb_deregister_dev (interface, &adu_class); -mutex_unlock (&dev->mtx);mutex_lock (&adutux_mutex);usb_set_intfdata (interface,NULL ); +mutex_lock (&dev->mtx);/* not interruptible */ + dev->udev =NULL ;/* poison */ +mutex_unlock (&dev->mtx); +/* if the device is not opened, then we clean up right now */ if (!dev->open_count)adu_delete (dev);
Signature · 1 line
2.23.0
PATCH 2/2 USB: adutux: fix NULL-derefs on disconnect
The driver was using its struct usb_device pointer as an inverted disconnected flag, but was setting it to NULL before making sure all completion handlers had run. This could lead to a NULL-pointer dereference in a number of dev_dbg statements in the completion handlers which relies on said pointer.
The pointer was also dereferenced unconditionally in a dev_dbg statement release() something which would lead to a NULL-deref whenever a device was disconnected before the final character-device close if debugging was enabled.
Fix this by unconditionally stopping all I/O and preventing resubmissions by poisoning the interrupt URBs at disconnect and using a dedicated disconnected flag.
This also makes sure that all I/O has completed by the time the disconnect callback returns.
--- drivers/usb/misc/adutux.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-)
drivers/usb/misc/adutux.c +10 -6
@@ -75,6 +75,7 @@ struct adu_device {char serial_number[8 ];int open_count;/* number of times this port has been opened */ + unsigned long disconnected:1;char *read_buffer_primary;int read_buffer_length;
@@ -116,7 +117,7 @@ static void adu_abort_transfers(struct adu_device *dev) {unsigned long flags; -if (dev->udev ==NULL ) +if (dev->disconnected)return ;/* shutdown transfer */
@@ -243,7 +244,7 @@ static int adu_open(struct inode *inode, struct file *file) } dev =usb_get_intfdata (interface); -if (!dev || !dev->udev) { +if (!dev) { retval = -ENODEV ; goto exit_no_device; }
@@ -326,7 +327,7 @@ static int adu_release(struct inode *inode, struct file *file) }adu_release_internal (dev); -if (dev->udev ==NULL ) { +if (dev->disconnected) {/* the device was unplugged before the file was released */ if (!dev->open_count)/* ... and we're the last user */ adu_delete (dev);
@@ -354,7 +355,7 @@ static ssize_t adu_read(struct file *file, __user char *buffer, size_t count,return -ERESTARTSYS ;/* verify that the device wasn't unplugged */ -if (dev->udev ==NULL ) { +if (dev->disconnected) { retval = -ENODEV ;pr_err ("No device or device unplugged %d\n" , retval); goto exit;
@@ -518,7 +519,7 @@ static ssize_t adu_write(struct file *file, const __user char *buffer, goto exit_nolock;/* verify that the device wasn't unplugged */ -if (dev->udev ==NULL ) { +if (dev->disconnected) { retval = -ENODEV ;pr_err ("No device or device unplugged %d\n" , retval); goto exit;
@@ -764,11 +765,14 @@ static void adu_disconnect(struct usb_interface *interface)usb_deregister_dev (interface, &adu_class); +usb_poison_urb (dev->interrupt_in_urb); +usb_poison_urb (dev->interrupt_out_urb); +mutex_lock (&adutux_mutex);usb_set_intfdata (interface,NULL );mutex_lock (&dev->mtx);/* not interruptible */ - dev->udev =NULL ;/* poison */ + dev->disconnected =1 ;mutex_unlock (&dev->mtx);/* if the device is not opened, then we clean up right now */
Signature · 1 line
2.23.0