| From a396f3a210c3a61e94d6b87ec05a75d0be2a60d0 Mon Sep 17 00:00:00 2001 |
| From: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> |
| Date: Mon, 2 Nov 2015 17:24:08 -0500 |
| Subject: xen/pciback: Do not install an IRQ handler for MSI interrupts. |
| |
| commit a396f3a210c3a61e94d6b87ec05a75d0be2a60d0 upstream. |
| |
| Otherwise an guest can subvert the generic MSI code to trigger |
| an BUG_ON condition during MSI interrupt freeing: |
| |
| for (i = 0; i < entry->nvec_used; i++) |
| BUG_ON(irq_has_action(entry->irq + i)); |
| |
| Xen PCI backed installs an IRQ handler (request_irq) for |
| the dev->irq whenever the guest writes PCI_COMMAND_MEMORY |
| (or PCI_COMMAND_IO) to the PCI_COMMAND register. This is |
| done in case the device has legacy interrupts the GSI line |
| is shared by the backend devices. |
| |
| To subvert the backend the guest needs to make the backend |
| to change the dev->irq from the GSI to the MSI interrupt line, |
| make the backend allocate an interrupt handler, and then command |
| the backend to free the MSI interrupt and hit the BUG_ON. |
| |
| Since the backend only calls 'request_irq' when the guest |
| writes to the PCI_COMMAND register the guest needs to call |
| XEN_PCI_OP_enable_msi before any other operation. This will |
| cause the generic MSI code to setup an MSI entry and |
| populate dev->irq with the new PIRQ value. |
| |
| Then the guest can write to PCI_COMMAND PCI_COMMAND_MEMORY |
| and cause the backend to setup an IRQ handler for dev->irq |
| (which instead of the GSI value has the MSI pirq). See |
| 'xen_pcibk_control_isr'. |
| |
| Then the guest disables the MSI: XEN_PCI_OP_disable_msi |
| which ends up triggering the BUG_ON condition in 'free_msi_irqs' |
| as there is an IRQ handler for the entry->irq (dev->irq). |
| |
| Note that this cannot be done using MSI-X as the generic |
| code does not over-write dev->irq with the MSI-X PIRQ values. |
| |
| The patch inhibits setting up the IRQ handler if MSI or |
| MSI-X (for symmetry reasons) code had been called successfully. |
| |
| P.S. |
| Xen PCIBack when it sets up the device for the guest consumption |
| ends up writting 0 to the PCI_COMMAND (see xen_pcibk_reset_device). |
| XSA-120 addendum patch removed that - however when upstreaming said |
| addendum we found that it caused issues with qemu upstream. That |
| has now been fixed in qemu upstream. |
| |
| This is part of XSA-157 |
| |
| Reviewed-by: David Vrabel <david.vrabel@citrix.com> |
| Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> |
| Signed-off-by: Zefan Li <lizefan@huawei.com> |
| --- |
| drivers/xen/xen-pciback/pciback_ops.c | 7 +++++++ |
| 1 file changed, 7 insertions(+) |
| |
| --- a/drivers/xen/xen-pciback/pciback_ops.c |
| +++ b/drivers/xen/xen-pciback/pciback_ops.c |
| @@ -69,6 +69,13 @@ static void xen_pcibk_control_isr(struct |
| enable ? "enable" : "disable"); |
| |
| if (enable) { |
| + /* |
| + * The MSI or MSI-X should not have an IRQ handler. Otherwise |
| + * if the guest terminates we BUG_ON in free_msi_irqs. |
| + */ |
| + if (dev->msi_enabled || dev->msix_enabled) |
| + goto out; |
| + |
| rc = request_irq(dev_data->irq, |
| xen_pcibk_guest_interrupt, IRQF_SHARED, |
| dev_data->irq_name, dev); |