hw/pcie: better hotplug/hotunplug support
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. Signed-off-by: Marcel Apfelbaum <marcel.a@redhat.com> Reviewed-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
This commit is contained in:
		
							parent
							
								
									f23b6bdc3c
								
							
						
					
					
						commit
						554f802da3
					
				| @ -258,7 +258,8 @@ void pcie_cap_slot_hotplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, | ||||
| 
 | ||||
|     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(HotplugHandler *hotplug_dev, DeviceState *dev, | ||||
| 
 | ||||
|     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
 | ||||
| @ -383,6 +381,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) | ||||
| { | ||||
| @ -407,6 +410,22 @@ void pcie_cap_slot_write_config(PCIDevice *dev, | ||||
|                         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); | ||||
| 
 | ||||
|     /* 
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Marcel Apfelbaum
						Marcel Apfelbaum