• Rafael J. Wysocki's avatar
    PCI: Check parent kobject in pci_destroy_dev() · 8a4c5c32
    Rafael J. Wysocki authored
    If pci_stop_and_remove_bus_device() is run concurrently for a device and
    its parent bridge via remove_callback(), both code paths attempt to acquire
    pci_rescan_remove_lock.  If the child device removal acquires it first,
    there will be no problems.  However, if the parent bridge removal acquires
    it first, it will eventually execute pci_destroy_dev() for the child
    device, but that device object will not be freed yet due to the reference
    held by the concurrent child removal.  Consequently, both
    pci_stop_bus_device() and pci_remove_bus_device() will be executed for that
    device unnecessarily and pci_destroy_dev() will see a corrupted list head
    in that object.  Moreover, an excess put_device() will be executed for that
    device in that case which may lead to a use-after-free in the final
    kobject_put() done by sysfs_schedule_callback_work().
    
    To avoid that problem, make pci_destroy_dev() check if the device's parent
    kobject is NULL, which only happens after device_del() has already run for
    it.  Make pci_destroy_dev() return immediately whithout doing anything in
    that case.
    Signed-off-by: default avatarRafael J. Wysocki <rafael.j.wysocki@intel.com>
    Signed-off-by: default avatarBjorn Helgaas <bhelgaas@google.com>
    8a4c5c32
remove.c 3.21 KB