summaryrefslogtreecommitdiffstats
path: root/sys/dev/usb/usb_dev.c
diff options
context:
space:
mode:
authorhselasky <hselasky@FreeBSD.org>2014-01-24 08:10:08 +0000
committerhselasky <hselasky@FreeBSD.org>2014-01-24 08:10:08 +0000
commit6e5156d6bb6755f251e480703c56db26ea69c02a (patch)
tree7e6f2f512b9261046f389034ef2aafa0d782d0e8 /sys/dev/usb/usb_dev.c
parentf692196495136a8dd592a7f06a940e6fae03fd6d (diff)
downloadFreeBSD-src-6e5156d6bb6755f251e480703c56db26ea69c02a.zip
FreeBSD-src-6e5156d6bb6755f251e480703c56db26ea69c02a.tar.gz
MFC r260808 and r260814:
- Close a minor deadlock. - Fix a possible memory use after free and leak situation associated with USB device detach when using character device handles. This also includes LibUSB. It turns out that "usb_close()" cannot always get a reference to clean up its USB transfers and such, if called during the kernel USB device detach.
Diffstat (limited to 'sys/dev/usb/usb_dev.c')
-rw-r--r--sys/dev/usb/usb_dev.c33
1 files changed, 17 insertions, 16 deletions
diff --git a/sys/dev/usb/usb_dev.c b/sys/dev/usb/usb_dev.c
index 9e3cef5..6a3080f 100644
--- a/sys/dev/usb/usb_dev.c
+++ b/sys/dev/usb/usb_dev.c
@@ -207,6 +207,11 @@ usb_ref_device(struct usb_cdev_privdata *cpd,
DPRINTFN(2, "no device at %u\n", cpd->dev_index);
goto error;
}
+ if (cpd->udev->state == USB_STATE_DETACHED &&
+ (need_uref != 2)) {
+ DPRINTFN(2, "device is detached\n");
+ goto error;
+ }
if (cpd->udev->refcount == USB_DEV_REF_MAX) {
DPRINTFN(2, "no dev ref\n");
goto error;
@@ -597,6 +602,13 @@ usb_fifo_free(struct usb_fifo *f)
mtx_unlock(f->priv_mtx);
mtx_lock(&usb_ref_lock);
+ /*
+ * Check if the "f->refcount" variable reached zero
+ * during the unlocked time before entering wait:
+ */
+ if (f->refcount == 0)
+ break;
+
/* wait for sync */
cv_wait(&f->cv_drain, &usb_ref_lock);
}
@@ -915,23 +927,12 @@ usb_close(void *arg)
DPRINTFN(2, "cpd=%p\n", cpd);
- err = usb_ref_device(cpd, &refs, 0);
- if (err)
+ err = usb_ref_device(cpd, &refs,
+ 2 /* uref and allow detached state */);
+ if (err) {
+ DPRINTFN(0, "Cannot grab USB reference when "
+ "closing USB file handle\n");
goto done;
-
- /*
- * If this function is not called directly from the root HUB
- * thread, there is usually a need to lock the enumeration
- * lock. Check this.
- */
- if (!usbd_enum_is_locked(cpd->udev)) {
-
- DPRINTFN(2, "Locking enumeration\n");
-
- /* reference device */
- err = usb_usb_ref_device(cpd, &refs);
- if (err)
- goto done;
}
if (cpd->fflags & FREAD) {
usb_fifo_close(refs.rxfifo, cpd->fflags);
OpenPOWER on IntegriCloud