Commit d64aac36394b3c26db53538bfedd8444a3a2206e
Committed by
Greg Kroah-Hartman
1 parent
61ad04a89f
Exists in
master
and in
20 other branches
usbfs: fix race between open and unregister
This patch (as1106) fixes a race between opening and unregistering device files in usbfs. The current code drops its reference to the device and then reacquires it, ignoring the possibility that the device structure might have been removed in the meantime. It also doesn't check whether the device is already in the NOTATTACHED state when the file is opened. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Showing 1 changed file with 11 additions and 5 deletions Side-by-side Diff
drivers/usb/core/devio.c
... | ... | @@ -562,7 +562,6 @@ |
562 | 562 | dev = bus_find_device(&usb_bus_type, NULL, (void *) devt, match_devt); |
563 | 563 | if (!dev) |
564 | 564 | return NULL; |
565 | - put_device(dev); | |
566 | 565 | return container_of(dev, struct usb_device, dev); |
567 | 566 | } |
568 | 567 | |
569 | 568 | |
570 | 569 | |
571 | 570 | |
... | ... | @@ -591,16 +590,21 @@ |
591 | 590 | dev = usbdev_lookup_by_devt(inode->i_rdev); |
592 | 591 | #ifdef CONFIG_USB_DEVICEFS |
593 | 592 | /* procfs file */ |
594 | - if (!dev) | |
593 | + if (!dev) { | |
595 | 594 | dev = inode->i_private; |
595 | + if (dev && dev->usbfs_dentry && | |
596 | + dev->usbfs_dentry->d_inode == inode) | |
597 | + usb_get_dev(dev); | |
598 | + else | |
599 | + dev = NULL; | |
600 | + } | |
596 | 601 | #endif |
597 | - if (!dev) | |
602 | + if (!dev || dev->state == USB_STATE_NOTATTACHED) | |
598 | 603 | goto out; |
599 | 604 | ret = usb_autoresume_device(dev); |
600 | 605 | if (ret) |
601 | 606 | goto out; |
602 | 607 | |
603 | - usb_get_dev(dev); | |
604 | 608 | ret = 0; |
605 | 609 | ps->dev = dev; |
606 | 610 | ps->file = file; |
607 | 611 | |
... | ... | @@ -620,8 +624,10 @@ |
620 | 624 | list_add_tail(&ps->list, &dev->filelist); |
621 | 625 | file->private_data = ps; |
622 | 626 | out: |
623 | - if (ret) | |
627 | + if (ret) { | |
624 | 628 | kfree(ps); |
629 | + usb_put_dev(dev); | |
630 | + } | |
625 | 631 | mutex_unlock(&usbfs_mutex); |
626 | 632 | unlock_kernel(); |
627 | 633 | return ret; |