--- /dev/null
+The current code is broken: it does surprise removal which crashes guests.
+
+Reimplemented the steps:
+ - Hotplug triggers both 'present detect change' and
+ 'attention button pressed'.
+
+ - Hotunplug starts by triggering 'attention button pressed',
+ then waits for the OS to power off the device and only
+ then detaches it.
+
+Fixes CVE-2014-3471.
+
+Originated-by: Marcel Apfelbaum <address@hidden>
+Updated-by: Daniel BORNAZ <daniel.bornaz@enea.com>
+
+--- a/hw/pci/pcie.c 2014-04-17 15:44:44.000000000 +0200
++++ b/hw/pci/pcie.c 2014-07-15 13:03:16.905070562 +0200
+@@ -258,7 +258,8 @@ void pcie_cap_slot_hotplug_cb(HotplugHan
+
+ pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTSTA,
+ PCI_EXP_SLTSTA_PDS);
+- pcie_cap_slot_event(PCI_DEVICE(hotplug_dev), PCI_EXP_HP_EV_PDC);
++ pcie_cap_slot_event(PCI_DEVICE(hotplug_dev),
++ PCI_EXP_HP_EV_PDC | PCI_EXP_HP_EV_ABP);
+ }
+
+ void pcie_cap_slot_hot_unplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
+@@ -268,10 +269,7 @@ void pcie_cap_slot_hot_unplug_cb(Hotplug
+
+ pcie_cap_slot_hotplug_common(PCI_DEVICE(hotplug_dev), dev, &exp_cap, errp);
+
+- object_unparent(OBJECT(dev));
+- pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTSTA,
+- PCI_EXP_SLTSTA_PDS);
+- pcie_cap_slot_event(PCI_DEVICE(hotplug_dev), PCI_EXP_HP_EV_PDC);
++ pcie_cap_slot_push_attention_button(PCI_DEVICE(hotplug_dev));
+ }
+
+ /* pci express slot for pci express root/downstream port
+@@ -352,6 +350,11 @@ void pcie_cap_slot_reset(PCIDevice *dev)
+ hotplug_event_update_event_status(dev);
+ }
+
++static void pcie_unplug_device(PCIBus *bus, PCIDevice *dev, void *opaque)
++{
++ object_unparent(OBJECT(dev));
++}
++
+ void pcie_cap_slot_write_config(PCIDevice *dev,
+ uint32_t addr, uint32_t val, int len)
+ {
+@@ -376,6 +379,22 @@ void pcie_cap_slot_write_config(PCIDevic
+ sltsta);
+ }
+
++ /*
++ * If the slot is polulated, power indicator is off and power
++ * controller is off, it is safe to detach the devices.
++ */
++ if ((sltsta & PCI_EXP_SLTSTA_PDS) && (val & PCI_EXP_SLTCTL_PCC) &&
++ ((val & PCI_EXP_SLTCTL_PIC_OFF) == PCI_EXP_SLTCTL_PIC_OFF)) {
++ PCIBus *sec_bus = pci_bridge_get_sec_bus(PCI_BRIDGE(dev));
++ pci_for_each_device(sec_bus, pci_bus_num(sec_bus),
++ pcie_unplug_device, NULL);
++
++ pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTSTA,
++ PCI_EXP_SLTSTA_PDS);
++ pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTSTA,
++ PCI_EXP_SLTSTA_PDC);
++ }
++
+ hotplug_event_notify(dev);
+
+ /*