* [PATCH 1/5] USB: adutux: fix use-after-free on release
[not found] <20191009153848.8664-1-johan@kernel.org>
@ 2019-10-09 15:38 ` Johan Hovold
2019-10-09 15:38 ` [PATCH 2/5] USB: chaoskey: " Johan Hovold
` (3 subsequent siblings)
4 siblings, 0 replies; 7+ messages in thread
From: Johan Hovold @ 2019-10-09 15:38 UTC (permalink / raw)
To: Greg Kroah-Hartman
Cc: linux-usb, Keith Packard, Juergen Stuber, Johan Hovold, stable
The driver was accessing its struct usb_device in its release()
callback without holding a reference. This would lead to a
use-after-free whenever the device was disconnected while the character
device was still open.
Fixes: 66d4bc30d128 ("USB: adutux: remove custom debug macro")
Cc: stable <stable@vger.kernel.org> # 3.12
Signed-off-by: Johan Hovold <johan@kernel.org>
---
drivers/usb/misc/adutux.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/usb/misc/adutux.c b/drivers/usb/misc/adutux.c
index f9efec719359..6f5edb9fc61e 100644
--- a/drivers/usb/misc/adutux.c
+++ b/drivers/usb/misc/adutux.c
@@ -149,6 +149,7 @@ static void adu_delete(struct adu_device *dev)
kfree(dev->read_buffer_secondary);
kfree(dev->interrupt_in_buffer);
kfree(dev->interrupt_out_buffer);
+ usb_put_dev(dev->udev);
kfree(dev);
}
@@ -664,7 +665,7 @@ static int adu_probe(struct usb_interface *interface,
mutex_init(&dev->mtx);
spin_lock_init(&dev->buflock);
- dev->udev = udev;
+ dev->udev = usb_get_dev(udev);
init_waitqueue_head(&dev->read_wait);
init_waitqueue_head(&dev->write_wait);
--
2.23.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH 2/5] USB: chaoskey: fix use-after-free on release
[not found] <20191009153848.8664-1-johan@kernel.org>
2019-10-09 15:38 ` [PATCH 1/5] USB: adutux: fix use-after-free on release Johan Hovold
@ 2019-10-09 15:38 ` Johan Hovold
2019-10-09 15:38 ` [PATCH 3/5] USB: ldusb: fix NULL-derefs on driver unbind Johan Hovold
` (2 subsequent siblings)
4 siblings, 0 replies; 7+ messages in thread
From: Johan Hovold @ 2019-10-09 15:38 UTC (permalink / raw)
To: Greg Kroah-Hartman
Cc: linux-usb, Keith Packard, Juergen Stuber, Johan Hovold, stable
The driver was accessing its struct usb_interface in its release()
callback without holding a reference. This would lead to a
use-after-free whenever the device was disconnected while the character
device was still open.
Fixes: 66e3e591891d ("usb: Add driver for Altus Metrum ChaosKey device (v2)")
Cc: stable <stable@vger.kernel.org> # 4.1
Signed-off-by: Johan Hovold <johan@kernel.org>
---
drivers/usb/misc/chaoskey.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/drivers/usb/misc/chaoskey.c b/drivers/usb/misc/chaoskey.c
index cf5828ce927a..34e6cd6f40d3 100644
--- a/drivers/usb/misc/chaoskey.c
+++ b/drivers/usb/misc/chaoskey.c
@@ -98,6 +98,7 @@ static void chaoskey_free(struct chaoskey *dev)
usb_free_urb(dev->urb);
kfree(dev->name);
kfree(dev->buf);
+ usb_put_intf(dev->interface);
kfree(dev);
}
}
@@ -145,6 +146,8 @@ static int chaoskey_probe(struct usb_interface *interface,
if (dev == NULL)
goto out;
+ dev->interface = usb_get_intf(interface);
+
dev->buf = kmalloc(size, GFP_KERNEL);
if (dev->buf == NULL)
@@ -174,8 +177,6 @@ static int chaoskey_probe(struct usb_interface *interface,
goto out;
}
- dev->interface = interface;
-
dev->in_ep = in_ep;
if (le16_to_cpu(udev->descriptor.idVendor) != ALEA_VENDOR_ID)
--
2.23.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH 3/5] USB: ldusb: fix NULL-derefs on driver unbind
[not found] <20191009153848.8664-1-johan@kernel.org>
2019-10-09 15:38 ` [PATCH 1/5] USB: adutux: fix use-after-free on release Johan Hovold
2019-10-09 15:38 ` [PATCH 2/5] USB: chaoskey: " Johan Hovold
@ 2019-10-09 15:38 ` Johan Hovold
2019-10-09 15:38 ` [PATCH 4/5] USB: legousbtower: fix use-after-free on release Johan Hovold
2019-10-09 15:38 ` [PATCH 5/5] USB: yurex: fix NULL-derefs on disconnect Johan Hovold
4 siblings, 0 replies; 7+ messages in thread
From: Johan Hovold @ 2019-10-09 15:38 UTC (permalink / raw)
To: Greg Kroah-Hartman
Cc: linux-usb, Keith Packard, Juergen Stuber, Johan Hovold, stable
The driver was using its struct usb_interface 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, dev_warn and dev_err statements in
the completion handlers which relies on said pointer.
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.
Fixes: 2824bd250f0b ("[PATCH] USB: add ldusb driver")
Cc: stable <stable@vger.kernel.org> # 2.6.13
Signed-off-by: Johan Hovold <johan@kernel.org>
---
drivers/usb/misc/ldusb.c | 24 ++++++++++++------------
1 file changed, 12 insertions(+), 12 deletions(-)
diff --git a/drivers/usb/misc/ldusb.c b/drivers/usb/misc/ldusb.c
index 6581774bdfa4..f3108d85e768 100644
--- a/drivers/usb/misc/ldusb.c
+++ b/drivers/usb/misc/ldusb.c
@@ -153,6 +153,7 @@ MODULE_PARM_DESC(min_interrupt_out_interval, "Minimum interrupt out interval in
struct ld_usb {
struct mutex mutex; /* locks this structure */
struct usb_interface *intf; /* save off the usb interface pointer */
+ unsigned long disconnected:1;
int open_count; /* number of times this port has been opened */
@@ -192,12 +193,10 @@ static void ld_usb_abort_transfers(struct ld_usb *dev)
/* shutdown transfer */
if (dev->interrupt_in_running) {
dev->interrupt_in_running = 0;
- if (dev->intf)
- usb_kill_urb(dev->interrupt_in_urb);
+ usb_kill_urb(dev->interrupt_in_urb);
}
if (dev->interrupt_out_busy)
- if (dev->intf)
- usb_kill_urb(dev->interrupt_out_urb);
+ usb_kill_urb(dev->interrupt_out_urb);
}
/**
@@ -205,8 +204,6 @@ static void ld_usb_abort_transfers(struct ld_usb *dev)
*/
static void ld_usb_delete(struct ld_usb *dev)
{
- ld_usb_abort_transfers(dev);
-
/* free data structures */
usb_free_urb(dev->interrupt_in_urb);
usb_free_urb(dev->interrupt_out_urb);
@@ -263,7 +260,7 @@ static void ld_usb_interrupt_in_callback(struct urb *urb)
resubmit:
/* resubmit if we're still running */
- if (dev->interrupt_in_running && !dev->buffer_overflow && dev->intf) {
+ if (dev->interrupt_in_running && !dev->buffer_overflow) {
retval = usb_submit_urb(dev->interrupt_in_urb, GFP_ATOMIC);
if (retval) {
dev_err(&dev->intf->dev,
@@ -392,7 +389,7 @@ static int ld_usb_release(struct inode *inode, struct file *file)
retval = -ENODEV;
goto unlock_exit;
}
- if (dev->intf == NULL) {
+ if (dev->disconnected) {
/* the device was unplugged before the file was released */
mutex_unlock(&dev->mutex);
/* unlock here as ld_usb_delete frees dev */
@@ -423,7 +420,7 @@ static __poll_t ld_usb_poll(struct file *file, poll_table *wait)
dev = file->private_data;
- if (!dev->intf)
+ if (dev->disconnected)
return EPOLLERR | EPOLLHUP;
poll_wait(file, &dev->read_wait, wait);
@@ -462,7 +459,7 @@ static ssize_t ld_usb_read(struct file *file, char __user *buffer, size_t count,
}
/* verify that the device wasn't unplugged */
- if (dev->intf == NULL) {
+ if (dev->disconnected) {
retval = -ENODEV;
printk(KERN_ERR "ldusb: No device or device unplugged %d\n", retval);
goto unlock_exit;
@@ -542,7 +539,7 @@ static ssize_t ld_usb_write(struct file *file, const char __user *buffer,
}
/* verify that the device wasn't unplugged */
- if (dev->intf == NULL) {
+ if (dev->disconnected) {
retval = -ENODEV;
printk(KERN_ERR "ldusb: No device or device unplugged %d\n", retval);
goto unlock_exit;
@@ -764,6 +761,9 @@ static void ld_usb_disconnect(struct usb_interface *intf)
/* give back our minor */
usb_deregister_dev(intf, &ld_usb_class);
+ usb_poison_urb(dev->interrupt_in_urb);
+ usb_poison_urb(dev->interrupt_out_urb);
+
mutex_lock(&dev->mutex);
/* if the device is not opened, then we clean up right now */
@@ -771,7 +771,7 @@ static void ld_usb_disconnect(struct usb_interface *intf)
mutex_unlock(&dev->mutex);
ld_usb_delete(dev);
} else {
- dev->intf = NULL;
+ dev->disconnected = 1;
/* wake up pollers */
wake_up_interruptible_all(&dev->read_wait);
wake_up_interruptible_all(&dev->write_wait);
--
2.23.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH 4/5] USB: legousbtower: fix use-after-free on release
[not found] <20191009153848.8664-1-johan@kernel.org>
` (2 preceding siblings ...)
2019-10-09 15:38 ` [PATCH 3/5] USB: ldusb: fix NULL-derefs on driver unbind Johan Hovold
@ 2019-10-09 15:38 ` Johan Hovold
2019-10-09 15:38 ` [PATCH 5/5] USB: yurex: fix NULL-derefs on disconnect Johan Hovold
4 siblings, 0 replies; 7+ messages in thread
From: Johan Hovold @ 2019-10-09 15:38 UTC (permalink / raw)
To: Greg Kroah-Hartman
Cc: linux-usb, Keith Packard, Juergen Stuber, Johan Hovold, stable
The driver was accessing its struct usb_device in its release()
callback without holding a reference. This would lead to a
use-after-free whenever the device was disconnected while the character
device was still open.
Fixes: fef526cae700 ("USB: legousbtower: remove custom debug macro")
Cc: stable <stable@vger.kernel.org> # 3.12
Signed-off-by: Johan Hovold <johan@kernel.org>
---
drivers/usb/misc/legousbtower.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/usb/misc/legousbtower.c b/drivers/usb/misc/legousbtower.c
index 44d6a3381804..9d4c52a7ebe0 100644
--- a/drivers/usb/misc/legousbtower.c
+++ b/drivers/usb/misc/legousbtower.c
@@ -296,6 +296,7 @@ static inline void tower_delete (struct lego_usb_tower *dev)
kfree (dev->read_buffer);
kfree (dev->interrupt_in_buffer);
kfree (dev->interrupt_out_buffer);
+ usb_put_dev(dev->udev);
kfree (dev);
}
@@ -810,7 +811,7 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device
mutex_init(&dev->lock);
- dev->udev = udev;
+ dev->udev = usb_get_dev(udev);
dev->open_count = 0;
dev->disconnected = 0;
--
2.23.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH 5/5] USB: yurex: fix NULL-derefs on disconnect
[not found] <20191009153848.8664-1-johan@kernel.org>
` (3 preceding siblings ...)
2019-10-09 15:38 ` [PATCH 4/5] USB: legousbtower: fix use-after-free on release Johan Hovold
@ 2019-10-09 15:38 ` Johan Hovold
2019-10-10 11:05 ` Johan Hovold
4 siblings, 1 reply; 7+ messages in thread
From: Johan Hovold @ 2019-10-09 15:38 UTC (permalink / raw)
To: Greg Kroah-Hartman
Cc: linux-usb, Keith Packard, Juergen Stuber, Johan Hovold, stable
The driver was using its struct usb_interface pointer as an inverted
disconnected flag, but was setting it to NULL without making sure all
code paths that used it were done with it.
Before commit ef61eb43ada6 ("USB: yurex: Fix protection fault after
device removal") this included the interrupt-in completion handler, but
there are further accesses in dev_err and dev_dbg statements in
yurex_write() and the driver-data destructor (sic!).
Fix this by unconditionally stopping also the control URB at disconnect
and by using a dedicated disconnected flag.
Note that we need to take a reference to the struct usb_interface to
avoid a use-after-free in the destructor whenever the device was
disconnected while the character device was still open.
Fixes: aadd6472d904 ("USB: yurex.c: remove dbg() usage")
Fixes: 45714104b9e8 ("USB: yurex.c: remove err() usage")
Cc: stable <stable@vger.kernel.org> # 3.5: ef61eb43ada6
Signed-off-by: Johan Hovold <johan@kernel.org>
---
drivers/usb/misc/yurex.c | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/drivers/usb/misc/yurex.c b/drivers/usb/misc/yurex.c
index 8d52d4336c29..be0505b8b5d4 100644
--- a/drivers/usb/misc/yurex.c
+++ b/drivers/usb/misc/yurex.c
@@ -60,6 +60,7 @@ struct usb_yurex {
struct kref kref;
struct mutex io_mutex;
+ unsigned long disconnected:1;
struct fasync_struct *async_queue;
wait_queue_head_t waitq;
@@ -107,6 +108,7 @@ static void yurex_delete(struct kref *kref)
dev->int_buffer, dev->urb->transfer_dma);
usb_free_urb(dev->urb);
}
+ usb_put_intf(dev->interface);
usb_put_dev(dev->udev);
kfree(dev);
}
@@ -205,7 +207,7 @@ static int yurex_probe(struct usb_interface *interface, const struct usb_device_
init_waitqueue_head(&dev->waitq);
dev->udev = usb_get_dev(interface_to_usbdev(interface));
- dev->interface = interface;
+ dev->interface = usb_get_intf(interface);
/* set up the endpoint information */
iface_desc = interface->cur_altsetting;
@@ -316,8 +318,9 @@ static void yurex_disconnect(struct usb_interface *interface)
/* prevent more I/O from starting */
usb_poison_urb(dev->urb);
+ usb_poison_urb(dev->cntl_urb);
mutex_lock(&dev->io_mutex);
- dev->interface = NULL;
+ dev->disconnected = 1;
mutex_unlock(&dev->io_mutex);
/* wakeup waiters */
@@ -405,7 +408,7 @@ static ssize_t yurex_read(struct file *file, char __user *buffer, size_t count,
dev = file->private_data;
mutex_lock(&dev->io_mutex);
- if (!dev->interface) { /* already disconnected */
+ if (dev->disconnected) { /* already disconnected */
mutex_unlock(&dev->io_mutex);
return -ENODEV;
}
@@ -440,7 +443,7 @@ static ssize_t yurex_write(struct file *file, const char __user *user_buffer,
goto error;
mutex_lock(&dev->io_mutex);
- if (!dev->interface) { /* already disconnected */
+ if (dev->disconnected) { /* already disconnected */
mutex_unlock(&dev->io_mutex);
retval = -ENODEV;
goto error;
--
2.23.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH 5/5] USB: yurex: fix NULL-derefs on disconnect
2019-10-09 15:38 ` [PATCH 5/5] USB: yurex: fix NULL-derefs on disconnect Johan Hovold
@ 2019-10-10 11:05 ` Johan Hovold
2019-10-10 12:24 ` Greg Kroah-Hartman
0 siblings, 1 reply; 7+ messages in thread
From: Johan Hovold @ 2019-10-10 11:05 UTC (permalink / raw)
To: Greg Kroah-Hartman
Cc: linux-usb, Keith Packard, Juergen Stuber, Johan Hovold, stable
On Wed, Oct 09, 2019 at 05:38:48PM +0200, Johan Hovold wrote:
> The driver was using its struct usb_interface pointer as an inverted
> disconnected flag, but was setting it to NULL without making sure all
> code paths that used it were done with it.
>
> Before commit ef61eb43ada6 ("USB: yurex: Fix protection fault after
> device removal") this included the interrupt-in completion handler, but
> there are further accesses in dev_err and dev_dbg statements in
> yurex_write() and the driver-data destructor (sic!).
>
> Fix this by unconditionally stopping also the control URB at disconnect
> and by using a dedicated disconnected flag.
>
> Note that we need to take a reference to the struct usb_interface to
> avoid a use-after-free in the destructor whenever the device was
> disconnected while the character device was still open.
>
> Fixes: aadd6472d904 ("USB: yurex.c: remove dbg() usage")
> Fixes: 45714104b9e8 ("USB: yurex.c: remove err() usage")
> Cc: stable <stable@vger.kernel.org> # 3.5: ef61eb43ada6
> Signed-off-by: Johan Hovold <johan@kernel.org>
Greg, I noticed that you picked up all patches in this series except
this last one.
Was that one purpose or by mistake?
Johan
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH 5/5] USB: yurex: fix NULL-derefs on disconnect
2019-10-10 11:05 ` Johan Hovold
@ 2019-10-10 12:24 ` Greg Kroah-Hartman
0 siblings, 0 replies; 7+ messages in thread
From: Greg Kroah-Hartman @ 2019-10-10 12:24 UTC (permalink / raw)
To: Johan Hovold; +Cc: linux-usb, Keith Packard, Juergen Stuber, stable
On Thu, Oct 10, 2019 at 01:05:32PM +0200, Johan Hovold wrote:
> On Wed, Oct 09, 2019 at 05:38:48PM +0200, Johan Hovold wrote:
> > The driver was using its struct usb_interface pointer as an inverted
> > disconnected flag, but was setting it to NULL without making sure all
> > code paths that used it were done with it.
> >
> > Before commit ef61eb43ada6 ("USB: yurex: Fix protection fault after
> > device removal") this included the interrupt-in completion handler, but
> > there are further accesses in dev_err and dev_dbg statements in
> > yurex_write() and the driver-data destructor (sic!).
> >
> > Fix this by unconditionally stopping also the control URB at disconnect
> > and by using a dedicated disconnected flag.
> >
> > Note that we need to take a reference to the struct usb_interface to
> > avoid a use-after-free in the destructor whenever the device was
> > disconnected while the character device was still open.
> >
> > Fixes: aadd6472d904 ("USB: yurex.c: remove dbg() usage")
> > Fixes: 45714104b9e8 ("USB: yurex.c: remove err() usage")
> > Cc: stable <stable@vger.kernel.org> # 3.5: ef61eb43ada6
> > Signed-off-by: Johan Hovold <johan@kernel.org>
>
> Greg, I noticed that you picked up all patches in this series except
> this last one.
>
> Was that one purpose or by mistake?
Mistake, thanks for catching that. Now queued up.
greg k-h
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2019-10-10 12:24 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
[not found] <20191009153848.8664-1-johan@kernel.org>
2019-10-09 15:38 ` [PATCH 1/5] USB: adutux: fix use-after-free on release Johan Hovold
2019-10-09 15:38 ` [PATCH 2/5] USB: chaoskey: " Johan Hovold
2019-10-09 15:38 ` [PATCH 3/5] USB: ldusb: fix NULL-derefs on driver unbind Johan Hovold
2019-10-09 15:38 ` [PATCH 4/5] USB: legousbtower: fix use-after-free on release Johan Hovold
2019-10-09 15:38 ` [PATCH 5/5] USB: yurex: fix NULL-derefs on disconnect Johan Hovold
2019-10-10 11:05 ` Johan Hovold
2019-10-10 12:24 ` Greg Kroah-Hartman
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).