linux/drivers/pci
Sebastian Andrzej Siewior 4ae2182b1e PCI/AER: Flush workqueue on device remove to avoid use-after-free
A Root Port's AER structure (rpc) contains a queue of events.  aer_irq()
enqueues AER status information and schedules aer_isr() to dequeue and
process it.  When we remove a device, aer_remove() waits for the queue to
be empty, then frees the rpc struct.

But aer_isr() references the rpc struct after dequeueing and possibly
emptying the queue, which can cause a use-after-free error as in the
following scenario with two threads, aer_isr() on the left and a
concurrent aer_remove() on the right:

  Thread A                      Thread B
  --------                      --------
  aer_irq():
    rpc->prod_idx++
                                aer_remove():
                                  wait_event(rpc->prod_idx == rpc->cons_idx)
                                  # now blocked until queue becomes empty
  aer_isr():                      # ...
    rpc->cons_idx++               # unblocked because queue is now empty
    ...                           kfree(rpc)
    mutex_unlock(&rpc->rpc_mutex)

To prevent this problem, use flush_work() to wait until the last scheduled
instance of aer_isr() has completed before freeing the rpc struct in
aer_remove().

I reproduced this use-after-free by flashing a device FPGA and
re-enumerating the bus to find the new device.  With SLUB debug, this
crashes with 0x6b bytes (POISON_FREE, the use-after-free magic number) in
GPR25:

  pcieport 0000:00:00.0: AER: Multiple Corrected error received: id=0000
  Unable to handle kernel paging request for data at address 0x27ef9e3e
  Workqueue: events aer_isr
  GPR24: dd6aa000 6b6b6b6b 605f8378 605f8360 d99b12c0 604fc674 606b1704 d99b12c0
  NIP [602f5328] pci_walk_bus+0xd4/0x104

[bhelgaas: changelog, stable tag]
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
CC: stable@vger.kernel.org
2016-01-25 10:08:00 -06:00
..
host PCI changes for the v4.5 merge window: 2016-01-21 11:52:16 -08:00
hotplug Merge branch 'pci/trivial' into next 2016-01-20 11:48:25 -06:00
pcie PCI/AER: Flush workqueue on device remove to avoid use-after-free 2016-01-25 10:08:00 -06:00
access.c PCI: Fix all whitespace issues 2016-01-08 10:35:24 -06:00
ats.c PCI: Remove pci_ats_enabled() 2015-08-13 15:59:59 -05:00
bus.c PCI: Fix minimum allocation address overwrite 2016-01-06 15:37:55 -06:00
host-bridge.c Merge branch 'pci/misc' into next 2015-04-10 08:27:18 -05:00
hotplug-pci.c PCI: Remove unnecessary __ref annotations 2014-04-29 17:36:44 -06:00
htirq.c x86/htirq: Use hierarchical irqdomain to manage Hypertransport interrupts 2015-04-24 15:36:50 +02:00
iov.c Merge branches 'pci/aer', 'pci/hotplug', 'pci/misc', 'pci/msi', 'pci/resource' and 'pci/virtualization' into next 2015-11-02 15:57:03 -06:00
irq.c
Kconfig PCI,parisc: Enable 64-bit bus addresses on PA-RISC 2015-09-08 15:30:47 +02:00
Makefile PCI: Build setup-irq.o for arm64 2015-08-20 12:02:49 -05:00
msi.c PCI changes for the v4.5 merge window: 2016-01-21 11:52:16 -08:00
of.c PCI/MSI: Use of_msi_get_domain instead of open-coded "msi-parent" parsing 2015-10-16 13:07:14 +01:00
pci-acpi.c Power management and ACPI updates for v4.5-rc1 2016-01-12 20:25:09 -08:00
pci-driver.c PCI / PM: Tune down retryable runtime suspend error messages 2015-12-02 15:24:21 +01:00
pci-label.c PCI: Use kobj_to_dev() instead of open-coding it 2016-01-08 12:07:57 -06:00
pci-stub.c PCI: Whitespace cleanup 2014-06-10 20:20:19 -06:00
pci-sysfs.c PCI changes for the v4.5 merge window: 2016-01-21 11:52:16 -08:00
pci.c PCI changes for the v4.5 merge window: 2016-01-21 11:52:16 -08:00
pci.h PCI changes for the v4.5 merge window: 2016-01-21 11:52:16 -08:00
probe.c PCI changes for the v4.5 merge window: 2016-01-21 11:52:16 -08:00
proc.c PCI: Whitespace cleanup 2014-06-10 20:20:19 -06:00
quirks.c PCI changes for the v4.5 merge window: 2016-01-21 11:52:16 -08:00
remove.c PCI: Embed ATS info directly into struct pci_dev 2015-08-13 15:57:21 -05:00
rom.c Merge branches 'pci/hotplug' and 'pci/resource' into next 2016-01-15 12:33:29 -06:00
search.c PCI: Delete unnecessary NULL pointer checks 2014-11-10 21:02:17 -07:00
setup-bus.c PCI: Fix all whitespace issues 2016-01-08 10:35:24 -06:00
setup-irq.c PCI: Export symbols required for loadable host driver modules 2015-04-08 14:17:10 -05:00
setup-res.c Merge branches 'pci/aer', 'pci/hotplug', 'pci/misc', 'pci/msi', 'pci/resource' and 'pci/virtualization' into next 2015-11-02 15:57:03 -06:00
slot.c PCI: Hold pci_slot_mutex while searching bus->slots list 2015-07-30 16:19:53 -05:00
syscall.c PCI: Whitespace cleanup 2014-06-10 20:20:19 -06:00
vc.c PCI: Use dev->has_secondary_link to find downstream PCIe links 2015-05-29 15:35:26 -05:00
vpd.c
xen-pcifront.c PCI: Use for_each_pci_msi_entry() to access MSI device list 2015-07-22 18:37:43 +02:00