[prev in list] [next in list] [prev in thread] [next in thread] 

List:       oss-security
Subject:    [oss-security] Xen Security Advisory 126 (CVE-2015-2756) - Unmediated PCI command register access in
From:       Xen.org security team <security () xen ! org>
Date:       2015-03-31 12:10:03
Message-ID: E1Ycuzb-0005NW-CJ () xenbits ! xen ! org
[Download RAW message or body]

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

            Xen Security Advisory CVE-2015-2756 / XSA-126
                              version 3

             Unmediated PCI command register access in qemu

UPDATES IN VERSION 3
====================

Public release.

ISSUE DESCRIPTION
=================

HVM guests are currently permitted to modify the memory and I/O decode
bits in the PCI command register of devices passed through to them.
Unless the device is an SR-IOV virtual function, after disabling one or
both of these bits subsequent accesses to the MMIO or I/O port ranges
would - on PCI Express devices - lead to Unsupported Request responses.
The treatment of such errors is platform specific.

Furthermore (at least) devices under control of the Linux pciback
driver in the host are handed to guests with the aforementioned bits
turned off.  This means that such accesses can similarly lead to
Unsupported Request responses until these flags are set as needed by
the guest.

IMPACT
======

In the event that the platform surfaces aforementioned UR responses as
Non-Maskable Interrupts, and either the OS is configured to treat NMIs
as fatal or (e.g. via ACPI's APEI) the platform tells the OS to treat
these errors as fatal, the host would crash, leading to a Denial of
Service.

VULNERABLE SYSTEMS
==================

Xen versions 3.3 and onwards are vulnerable due to supporting PCI
pass-through.

Only x86 systems are vulnerable.  ARM systems are not vulnerable.

Only HVM guests with their device model run in Dom0 can take advantage
of this vulnerability.

Any domain which is given access to a non-SR-IOV virtual function PCI
Express device can take advantage of this vulnerability.

MITIGATION
==========

This issue can be avoided by not assigning PCI Express devices other
than SR-IOV virtual functions to untrusted HVM guests.  This issue can
also be avoided by only using PV guests or HVM guests with their
device model run in a separate (stub) domain.

CREDITS
=======

This issue was discovered by Jan Beulich of SUSE.

RESOLUTION
==========

Applying the appropriate attached patch resolves this issue.

xsa126-qemuu.patch           qemu-upstream-unstable, Xen 4.5.x, Xen 4.4.x
xsa126-qemuu-4.3.patch       qemu-upstream-unstable, Xen 4.3.x
xsa126-qemut.patch           qemu-xen-unstable, Xen 4.5.x, Xen 4.4.x, Xen 4.3.x, Xen 4.2.x

For those already having the original patch in place, applying the
appropriate attached incremental patch addresses the regression.

xsa126-qemuu-incr.patch      qemu-upstream-unstable, Xen 4.5.x, Xen 4.4.x
xsa126-qemuu-4.3-incr.patch  qemu-upstream-unstable, Xen 4.3.x
xsa126-qemut-incr.patch      qemu-xen-unstable, Xen 4.5.x, Xen 4.4.x, Xen 4.3.x, Xen 4.2.x

$ sha256sum xsa126*.patch
bd69a0d18127793a9aa2097062ecaef76df6e6b8f729406d7d52cf66519e3b0d  xsa126-qemut-incr.patch
2a9b8f73b2a4f0cfb6b724c9a0a72dbf08cae87cd382f61f563218c32d1036a7  xsa126-qemut.patch
658bc483d1110e4e04de2d70fba1cdb20c5cecdc2f419db2d82bddc3ae1690b6  xsa126-qemuu-4.3-incr.patch
090d9262a9e9d24f0f4eca35cb0d56831d5cec6a6ba38b4c7e276d767de660c1  xsa126-qemuu-4.3.patch
3f7b6737c08ff7e119bec16c8c3b3cb832429f1410e687edf622fab57a22842e  xsa126-qemuu-incr.patch
eb5b93600267639b2cda1c5e2f937ddbecbf6c8cbd19dbb355224c39c2e40d3e  xsa126-qemuu.patch
$

DEPLOYMENT DURING EMBARGO
=========================

Deployment of the patches and/or mitigations described above (or
others which are substantially similar) is permitted during the
embargo, even on public-facing systems with untrusted guest users and
administrators.

But: Distribution of updated software is prohibited (except to other
members of the predisclosure list).

Predisclosure list members who wish to deploy significantly different
patches and/or mitigations, please contact the Xen Project Security
Team.

(Note: this during-embargo deployment notice is retained in
post-embargo publicly released Xen Project advisories, even though it
is then no longer applicable.  This is to enable the community to have
oversight of the Xen Project Security Team's decisionmaking.)

For more information about permissible uses of embargoed information,
consult the Xen Project community's agreed Security Policy:
  http://www.xenproject.org/security-policy.html
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.12 (GNU/Linux)

iQEcBAEBAgAGBQJVGo5NAAoJEIP+FMlX6CvZvt4IAIeNbTd6EQJE4CnuU6fH9lA3
0fO7FrUEMn7cfiptLy86y01C0d7YqF1MCbO3TKfJ0NJSjvl5CQ/WDuPwjdbD28eW
Zi2NZFRRy0JnLM3bgHxYB5Ik7voO6QPm4+BSZxM9rdiOhKwOY1LLyDbRlC5GvsVr
5J87gm1tfcQVHNDkVZp6ZlzQh5Kl3iSFp6KvzwsIagoJucsPVEHsoBWF84I+3peu
miT3gQqPeZg3PxplKNBkFZOr4hfE1vkYEmopnPY+ClSqsIB0XWM8XSbr8IByXI/E
VBAAsssFYV3mwNSoVrip+CWumi32ocikfxly+GlZxNWiMO4T57La6CJcmjQqaEE=
=wvTM
-----END PGP SIGNATURE-----

["xsa126-qemut-incr.patch" (application/octet-stream)]

xen: enable memory and I/O decoding before passing PCI device to guest

Otherwise, with v1 of the XSA-126 fix in place, nothing will do this,
leaving the device unusable except for malicious purposes.

This is part of CVE-2015-2756 / XSA-126.

Signed-off-by: Jan Beulich <jbeulich@suse.com>
Acked-by: Ian Campbell <ian.campbell@citrix.com>

--- a/hw/pass-through.c
+++ b/hw/pass-through.c
@@ -1905,7 +1905,7 @@ static int pt_dev_is_virtfn(struct pci_d
     return rc;
 }
 
-static int pt_register_regions(struct pt_dev *assigned_device)
+static int pt_register_regions(struct pt_dev *assigned_device, uint16_t *cmd)
 {
     int i = 0;
     uint32_t bar_data = 0;
@@ -1925,17 +1925,26 @@ static int pt_register_regions(struct pt
 
             /* Register current region */
             if ( pci_dev->base_addr[i] & PCI_ADDRESS_SPACE_IO )
+            {
                 pci_register_io_region((PCIDevice *)assigned_device, i,
                     (uint32_t)pci_dev->size[i], PCI_ADDRESS_SPACE_IO,
                     pt_ioport_map);
+                *cmd |= PCI_COMMAND_IO;
+            }
             else if ( pci_dev->base_addr[i] & PCI_ADDRESS_SPACE_MEM_PREFETCH )
+            {
                 pci_register_io_region((PCIDevice *)assigned_device, i,
                     (uint32_t)pci_dev->size[i], PCI_ADDRESS_SPACE_MEM_PREFETCH,
                     pt_iomem_map);
+                *cmd |= PCI_COMMAND_MEMORY;
+            }
             else
+            {
                 pci_register_io_region((PCIDevice *)assigned_device, i,
                     (uint32_t)pci_dev->size[i], PCI_ADDRESS_SPACE_MEM,
                     pt_iomem_map);
+                *cmd |= PCI_COMMAND_MEMORY;
+            }
 
             PT_LOG("IO region registered (size=0x%08x base_addr=0x%08x)\n",
                 (uint32_t)(pci_dev->size[i]),
@@ -4211,6 +4220,7 @@ static struct pt_dev * register_real_dev
     struct pt_dev *assigned_device = NULL;
     struct pci_dev *pci_dev;
     uint8_t e_device, e_intx;
+    uint16_t cmd = 0;
     char *key, *val;
     int msi_translate, power_mgmt;
 
@@ -4300,7 +4310,7 @@ static struct pt_dev * register_real_dev
         assigned_device->dev.config[i] = pci_read_byte(pci_dev, i);
 
     /* Handle real device's MMIO/PIO BARs */
-    pt_register_regions(assigned_device);
+    pt_register_regions(assigned_device, &cmd);
 
     /* Setup VGA bios for passthroughed gfx */
     if ( setup_vga_pt(assigned_device) < 0 )
@@ -4378,6 +4388,10 @@ static struct pt_dev * register_real_dev
     }
 
 out:
+    if (cmd)
+        pci_write_word(pci_dev, PCI_COMMAND,
+            *(uint16_t *)(&assigned_device->dev.config[PCI_COMMAND]) | cmd);
+
     PT_LOG("Real physical device %02x:%02x.%x registered successfuly!\n"
            "IRQ type = %s\n", r_bus, r_dev, r_func,
            assigned_device->msi_trans_en? "MSI-INTx":"INTx");

["xsa126-qemut.patch" (application/octet-stream)]

xen: limit guest control of PCI command register

Otherwise the guest can abuse that control to cause e.g. PCIe
Unsupported Request responses (by disabling memory and/or I/O decoding
and subsequently causing [CPU side] accesses to the respective address
ranges), which (depending on system configuration) may be fatal to the
host.

This is CVE-2015-2756 / XSA-126.

Signed-off-by: Jan Beulich <jbeulich@suse.com>
Reviewed-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
Acked-by: Ian Campbell <ian.campbell@citrix.com>

--- a/hw/pass-through.c
+++ b/hw/pass-through.c
@@ -172,9 +172,6 @@ static int pt_word_reg_read(struct pt_de
 static int pt_long_reg_read(struct pt_dev *ptdev,
     struct pt_reg_tbl *cfg_entry,
     uint32_t *value, uint32_t valid_mask);
-static int pt_cmd_reg_read(struct pt_dev *ptdev,
-    struct pt_reg_tbl *cfg_entry,
-    uint16_t *value, uint16_t valid_mask);
 static int pt_bar_reg_read(struct pt_dev *ptdev,
     struct pt_reg_tbl *cfg_entry,
     uint32_t *value, uint32_t valid_mask);
@@ -286,9 +283,9 @@ static struct pt_reg_info_tbl pt_emu_reg
         .size       = 2,
         .init_val   = 0x0000,
         .ro_mask    = 0xF880,
-        .emu_mask   = 0x0740,
+        .emu_mask   = 0x0743,
         .init       = pt_common_reg_init,
-        .u.w.read   = pt_cmd_reg_read,
+        .u.w.read   = pt_word_reg_read,
         .u.w.write  = pt_cmd_reg_write,
         .u.w.restore  = pt_cmd_reg_restore,
     },
@@ -1905,7 +1902,7 @@ static int pt_dev_is_virtfn(struct pci_d
     return rc;
 }
 
-static int pt_register_regions(struct pt_dev *assigned_device)
+static int pt_register_regions(struct pt_dev *assigned_device, uint16_t *cmd)
 {
     int i = 0;
     uint32_t bar_data = 0;
@@ -1925,17 +1922,26 @@ static int pt_register_regions(struct pt
 
             /* Register current region */
             if ( pci_dev->base_addr[i] & PCI_ADDRESS_SPACE_IO )
+            {
                 pci_register_io_region((PCIDevice *)assigned_device, i,
                     (uint32_t)pci_dev->size[i], PCI_ADDRESS_SPACE_IO,
                     pt_ioport_map);
+                *cmd |= PCI_COMMAND_IO;
+            }
             else if ( pci_dev->base_addr[i] & PCI_ADDRESS_SPACE_MEM_PREFETCH )
+            {
                 pci_register_io_region((PCIDevice *)assigned_device, i,
                     (uint32_t)pci_dev->size[i], PCI_ADDRESS_SPACE_MEM_PREFETCH,
                     pt_iomem_map);
+                *cmd |= PCI_COMMAND_MEMORY;
+            }
             else
+            {
                 pci_register_io_region((PCIDevice *)assigned_device, i,
                     (uint32_t)pci_dev->size[i], PCI_ADDRESS_SPACE_MEM,
                     pt_iomem_map);
+                *cmd |= PCI_COMMAND_MEMORY;
+            }
 
             PT_LOG("IO region registered (size=0x%08x base_addr=0x%08x)\n",
                 (uint32_t)(pci_dev->size[i]),
@@ -3263,27 +3269,6 @@ static int pt_long_reg_read(struct pt_de
    return 0;
 }
 
-/* read Command register */
-static int pt_cmd_reg_read(struct pt_dev *ptdev,
-        struct pt_reg_tbl *cfg_entry,
-        uint16_t *value, uint16_t valid_mask)
-{
-    struct pt_reg_info_tbl *reg = cfg_entry->reg;
-    uint16_t valid_emu_mask = 0;
-    uint16_t emu_mask = reg->emu_mask;
-
-    if ( ptdev->is_virtfn )
-        emu_mask |= PCI_COMMAND_MEMORY;
-    if ( pt_is_iomul(ptdev) )
-        emu_mask |= PCI_COMMAND_IO;
-
-    /* emulate word register */
-    valid_emu_mask = emu_mask & valid_mask;
-    *value = PT_MERGE_VALUE(*value, cfg_entry->data, ~valid_emu_mask);
-
-    return 0;
-}
-
 /* read BAR */
 static int pt_bar_reg_read(struct pt_dev *ptdev,
         struct pt_reg_tbl *cfg_entry,
@@ -3418,19 +3403,13 @@ static int pt_cmd_reg_write(struct pt_de
     uint16_t writable_mask = 0;
     uint16_t throughable_mask = 0;
     uint16_t wr_value = *value;
-    uint16_t emu_mask = reg->emu_mask;
-
-    if ( ptdev->is_virtfn )
-        emu_mask |= PCI_COMMAND_MEMORY;
-    if ( pt_is_iomul(ptdev) )
-        emu_mask |= PCI_COMMAND_IO;
 
     /* modify emulate register */
     writable_mask = ~reg->ro_mask & valid_mask;
     cfg_entry->data = PT_MERGE_VALUE(*value, cfg_entry->data, writable_mask);
 
     /* create value for writing to I/O device register */
-    throughable_mask = ~emu_mask & valid_mask;
+    throughable_mask = ~reg->emu_mask & valid_mask;
 
     if (*value & PCI_COMMAND_DISABLE_INTx)
     {
@@ -4211,6 +4190,7 @@ static struct pt_dev * register_real_dev
     struct pt_dev *assigned_device = NULL;
     struct pci_dev *pci_dev;
     uint8_t e_device, e_intx;
+    uint16_t cmd = 0;
     char *key, *val;
     int msi_translate, power_mgmt;
 
@@ -4300,7 +4280,7 @@ static struct pt_dev * register_real_dev
         assigned_device->dev.config[i] = pci_read_byte(pci_dev, i);
 
     /* Handle real device's MMIO/PIO BARs */
-    pt_register_regions(assigned_device);
+    pt_register_regions(assigned_device, &cmd);
 
     /* Setup VGA bios for passthroughed gfx */
     if ( setup_vga_pt(assigned_device) < 0 )
@@ -4378,6 +4358,10 @@ static struct pt_dev * register_real_dev
     }
 
 out:
+    if (cmd)
+        pci_write_word(pci_dev, PCI_COMMAND,
+            *(uint16_t *)(&assigned_device->dev.config[PCI_COMMAND]) | cmd);
+
     PT_LOG("Real physical device %02x:%02x.%x registered successfuly!\n"
            "IRQ type = %s\n", r_bus, r_dev, r_func,
            assigned_device->msi_trans_en? "MSI-INTx":"INTx");

["xsa126-qemuu-4.3-incr.patch" (application/octet-stream)]

xen: enable memory and I/O decoding before passing PCI device to guest

Otherwise, with v1 of the XSA-126 fix in place, nothing will do this,
leaving the device unusable except for malicious purposes.

This is part of CVE-2015-2756 / XSA-126.

Signed-off-by: Jan Beulich <jbeulich@suse.com>
Acked-by: Ian Campbell <ian.campbell@citrix.com>

--- a/hw/xen_pt.c
+++ b/hw/xen_pt.c
@@ -388,7 +388,7 @@ static const MemoryRegionOps ops = {
     .write = xen_pt_bar_write,
 };
 
-static int xen_pt_register_regions(XenPCIPassthroughState *s)
+static int xen_pt_register_regions(XenPCIPassthroughState *s, uint16_t *cmd)
 {
     int i = 0;
     XenHostPCIDevice *d = &s->real_device;
@@ -406,6 +406,7 @@ static int xen_pt_register_regions(XenPC
 
         if (r->type & XEN_HOST_PCI_REGION_TYPE_IO) {
             type = PCI_BASE_ADDRESS_SPACE_IO;
+            *cmd |= PCI_COMMAND_IO;
         } else {
             type = PCI_BASE_ADDRESS_SPACE_MEMORY;
             if (r->type & XEN_HOST_PCI_REGION_TYPE_PREFETCH) {
@@ -414,6 +415,7 @@ static int xen_pt_register_regions(XenPC
             if (r->type & XEN_HOST_PCI_REGION_TYPE_MEM_64) {
                 type |= PCI_BASE_ADDRESS_MEM_TYPE_64;
             }
+            *cmd |= PCI_COMMAND_MEMORY;
         }
 
         memory_region_init_io(&s->bar[i], &ops, &s->dev,
@@ -652,6 +654,7 @@ static int xen_pt_initfn(PCIDevice *d)
     XenPCIPassthroughState *s = DO_UPCAST(XenPCIPassthroughState, dev, d);
     int rc = 0;
     uint8_t machine_irq = 0;
+    uint16_t cmd = 0;
     int pirq = XEN_PT_UNASSIGNED_PIRQ;
 
     /* register real device */
@@ -686,7 +689,7 @@ static int xen_pt_initfn(PCIDevice *d)
     s->io_listener = xen_pt_io_listener;
 
     /* Handle real device's MMIO/PIO BARs */
-    xen_pt_register_regions(s);
+    xen_pt_register_regions(s, &cmd);
 
     /* reinitialize each config register to be emulated */
     if (xen_pt_config_init(s)) {
@@ -750,6 +753,11 @@ static int xen_pt_initfn(PCIDevice *d)
     }
 
 out:
+    if (cmd) {
+        xen_host_pci_set_word(&s->real_device, PCI_COMMAND,
+                              pci_get_word(d->config + PCI_COMMAND) | cmd);
+    }
+
     memory_listener_register(&s->memory_listener, &address_space_memory);
     memory_listener_register(&s->io_listener, &address_space_io);
     XEN_PT_LOG(d, "Real physical device %02x:%02x.%d registered successfuly!\n",

["xsa126-qemuu-4.3.patch" (application/octet-stream)]

xen: limit guest control of PCI command register

Otherwise the guest can abuse that control to cause e.g. PCIe
Unsupported Request responses (by disabling memory and/or I/O decoding
and subsequently causing [CPU side] accesses to the respective address
ranges), which (depending on system configuration) may be fatal to the
host.

This is CVE-2015-2756 / XSA-126.

Signed-off-by: Jan Beulich <jbeulich@suse.com>
Reviewed-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
Acked-by: Ian Campbell <ian.campbell@citrix.com>

--- a/hw/xen_pt.c
+++ b/hw/xen_pt.c
@@ -388,7 +388,7 @@ static const MemoryRegionOps ops = {
     .write = xen_pt_bar_write,
 };
 
-static int xen_pt_register_regions(XenPCIPassthroughState *s)
+static int xen_pt_register_regions(XenPCIPassthroughState *s, uint16_t *cmd)
 {
     int i = 0;
     XenHostPCIDevice *d = &s->real_device;
@@ -406,6 +406,7 @@ static int xen_pt_register_regions(XenPC
 
         if (r->type & XEN_HOST_PCI_REGION_TYPE_IO) {
             type = PCI_BASE_ADDRESS_SPACE_IO;
+            *cmd |= PCI_COMMAND_IO;
         } else {
             type = PCI_BASE_ADDRESS_SPACE_MEMORY;
             if (r->type & XEN_HOST_PCI_REGION_TYPE_PREFETCH) {
@@ -414,6 +415,7 @@ static int xen_pt_register_regions(XenPC
             if (r->type & XEN_HOST_PCI_REGION_TYPE_MEM_64) {
                 type |= PCI_BASE_ADDRESS_MEM_TYPE_64;
             }
+            *cmd |= PCI_COMMAND_MEMORY;
         }
 
         memory_region_init_io(&s->bar[i], &ops, &s->dev,
@@ -652,6 +654,7 @@ static int xen_pt_initfn(PCIDevice *d)
     XenPCIPassthroughState *s = DO_UPCAST(XenPCIPassthroughState, dev, d);
     int rc = 0;
     uint8_t machine_irq = 0;
+    uint16_t cmd = 0;
     int pirq = XEN_PT_UNASSIGNED_PIRQ;
 
     /* register real device */
@@ -686,7 +689,7 @@ static int xen_pt_initfn(PCIDevice *d)
     s->io_listener = xen_pt_io_listener;
 
     /* Handle real device's MMIO/PIO BARs */
-    xen_pt_register_regions(s);
+    xen_pt_register_regions(s, &cmd);
 
     /* reinitialize each config register to be emulated */
     if (xen_pt_config_init(s)) {
@@ -750,6 +753,11 @@ static int xen_pt_initfn(PCIDevice *d)
     }
 
 out:
+    if (cmd) {
+        xen_host_pci_set_word(&s->real_device, PCI_COMMAND,
+                              pci_get_word(d->config + PCI_COMMAND) | cmd);
+    }
+
     memory_listener_register(&s->memory_listener, &address_space_memory);
     memory_listener_register(&s->io_listener, &address_space_io);
     XEN_PT_LOG(d, "Real physical device %02x:%02x.%d registered successfuly!\n",
--- a/hw/xen_pt_config_init.c
+++ b/hw/xen_pt_config_init.c
@@ -286,23 +286,6 @@ static int xen_pt_irqpin_reg_init(XenPCI
 }
 
 /* Command register */
-static int xen_pt_cmd_reg_read(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
-                               uint16_t *value, uint16_t valid_mask)
-{
-    XenPTRegInfo *reg = cfg_entry->reg;
-    uint16_t valid_emu_mask = 0;
-    uint16_t emu_mask = reg->emu_mask;
-
-    if (s->is_virtfn) {
-        emu_mask |= PCI_COMMAND_MEMORY;
-    }
-
-    /* emulate word register */
-    valid_emu_mask = emu_mask & valid_mask;
-    *value = XEN_PT_MERGE_VALUE(*value, cfg_entry->data, ~valid_emu_mask);
-
-    return 0;
-}
 static int xen_pt_cmd_reg_write(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
                                 uint16_t *val, uint16_t dev_value,
                                 uint16_t valid_mask)
@@ -310,18 +293,13 @@ static int xen_pt_cmd_reg_write(XenPCIPa
     XenPTRegInfo *reg = cfg_entry->reg;
     uint16_t writable_mask = 0;
     uint16_t throughable_mask = 0;
-    uint16_t emu_mask = reg->emu_mask;
-
-    if (s->is_virtfn) {
-        emu_mask |= PCI_COMMAND_MEMORY;
-    }
 
     /* modify emulate register */
     writable_mask = ~reg->ro_mask & valid_mask;
     cfg_entry->data = XEN_PT_MERGE_VALUE(*val, cfg_entry->data, writable_mask);
 
     /* create value for writing to I/O device register */
-    throughable_mask = ~emu_mask & valid_mask;
+    throughable_mask = ~reg->emu_mask & valid_mask;
 
     if (*val & PCI_COMMAND_INTX_DISABLE) {
         throughable_mask |= PCI_COMMAND_INTX_DISABLE;
@@ -605,9 +583,9 @@ static XenPTRegInfo xen_pt_emu_reg_heade
         .size       = 2,
         .init_val   = 0x0000,
         .ro_mask    = 0xF880,
-        .emu_mask   = 0x0740,
+        .emu_mask   = 0x0743,
         .init       = xen_pt_common_reg_init,
-        .u.w.read   = xen_pt_cmd_reg_read,
+        .u.w.read   = xen_pt_word_reg_read,
         .u.w.write  = xen_pt_cmd_reg_write,
     },
     /* Capabilities Pointer reg */

["xsa126-qemuu-incr.patch" (application/octet-stream)]

xen: enable memory and I/O decoding before passing PCI device to guest

Otherwise, with v1 of the XSA-126 fix in place, nothing will do this,
leaving the device unusable except for malicious purposes.

This is part of CVE-2015-2756 / XSA-126.

Signed-off-by: Jan Beulich <jbeulich@suse.com>
Acked-by: Ian Campbell <ian.campbell@citrix.com>

--- a/hw/xen/xen_pt.c
+++ b/hw/xen/xen_pt.c
@@ -388,7 +388,7 @@ static const MemoryRegionOps ops = {
     .write = xen_pt_bar_write,
 };
 
-static int xen_pt_register_regions(XenPCIPassthroughState *s)
+static int xen_pt_register_regions(XenPCIPassthroughState *s, uint16_t *cmd)
 {
     int i = 0;
     XenHostPCIDevice *d = &s->real_device;
@@ -406,6 +406,7 @@ static int xen_pt_register_regions(XenPC
 
         if (r->type & XEN_HOST_PCI_REGION_TYPE_IO) {
             type = PCI_BASE_ADDRESS_SPACE_IO;
+            *cmd |= PCI_COMMAND_IO;
         } else {
             type = PCI_BASE_ADDRESS_SPACE_MEMORY;
             if (r->type & XEN_HOST_PCI_REGION_TYPE_PREFETCH) {
@@ -414,6 +415,7 @@ static int xen_pt_register_regions(XenPC
             if (r->type & XEN_HOST_PCI_REGION_TYPE_MEM_64) {
                 type |= PCI_BASE_ADDRESS_MEM_TYPE_64;
             }
+            *cmd |= PCI_COMMAND_MEMORY;
         }
 
         memory_region_init_io(&s->bar[i], OBJECT(s), &ops, &s->dev,
@@ -638,6 +640,7 @@ static int xen_pt_initfn(PCIDevice *d)
     XenPCIPassthroughState *s = DO_UPCAST(XenPCIPassthroughState, dev, d);
     int rc = 0;
     uint8_t machine_irq = 0;
+    uint16_t cmd = 0;
     int pirq = XEN_PT_UNASSIGNED_PIRQ;
 
     /* register real device */
@@ -672,7 +675,7 @@ static int xen_pt_initfn(PCIDevice *d)
     s->io_listener = xen_pt_io_listener;
 
     /* Handle real device's MMIO/PIO BARs */
-    xen_pt_register_regions(s);
+    xen_pt_register_regions(s, &cmd);
 
     /* reinitialize each config register to be emulated */
     if (xen_pt_config_init(s)) {
@@ -736,6 +739,11 @@ static int xen_pt_initfn(PCIDevice *d)
     }
 
 out:
+    if (cmd) {
+        xen_host_pci_set_word(&s->real_device, PCI_COMMAND,
+                              pci_get_word(d->config + PCI_COMMAND) | cmd);
+    }
+
     memory_listener_register(&s->memory_listener, &address_space_memory);
     memory_listener_register(&s->io_listener, &address_space_io);
     XEN_PT_LOG(d,

["xsa126-qemuu.patch" (application/octet-stream)]

xen: limit guest control of PCI command register

Otherwise the guest can abuse that control to cause e.g. PCIe
Unsupported Request responses (by disabling memory and/or I/O decoding
and subsequently causing [CPU side] accesses to the respective address
ranges), which (depending on system configuration) may be fatal to the
host.

This is CVE-2015-2756 / XSA-126.

Signed-off-by: Jan Beulich <jbeulich@suse.com>
Reviewed-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
Acked-by: Ian Campbell <ian.campbell@citrix.com>

--- a/hw/xen/xen_pt.c
+++ b/hw/xen/xen_pt.c
@@ -388,7 +388,7 @@ static const MemoryRegionOps ops = {
     .write = xen_pt_bar_write,
 };
 
-static int xen_pt_register_regions(XenPCIPassthroughState *s)
+static int xen_pt_register_regions(XenPCIPassthroughState *s, uint16_t *cmd)
 {
     int i = 0;
     XenHostPCIDevice *d = &s->real_device;
@@ -406,6 +406,7 @@ static int xen_pt_register_regions(XenPC
 
         if (r->type & XEN_HOST_PCI_REGION_TYPE_IO) {
             type = PCI_BASE_ADDRESS_SPACE_IO;
+            *cmd |= PCI_COMMAND_IO;
         } else {
             type = PCI_BASE_ADDRESS_SPACE_MEMORY;
             if (r->type & XEN_HOST_PCI_REGION_TYPE_PREFETCH) {
@@ -414,6 +415,7 @@ static int xen_pt_register_regions(XenPC
             if (r->type & XEN_HOST_PCI_REGION_TYPE_MEM_64) {
                 type |= PCI_BASE_ADDRESS_MEM_TYPE_64;
             }
+            *cmd |= PCI_COMMAND_MEMORY;
         }
 
         memory_region_init_io(&s->bar[i], OBJECT(s), &ops, &s->dev,
@@ -638,6 +640,7 @@ static int xen_pt_initfn(PCIDevice *d)
     XenPCIPassthroughState *s = DO_UPCAST(XenPCIPassthroughState, dev, d);
     int rc = 0;
     uint8_t machine_irq = 0;
+    uint16_t cmd = 0;
     int pirq = XEN_PT_UNASSIGNED_PIRQ;
 
     /* register real device */
@@ -672,7 +675,7 @@ static int xen_pt_initfn(PCIDevice *d)
     s->io_listener = xen_pt_io_listener;
 
     /* Handle real device's MMIO/PIO BARs */
-    xen_pt_register_regions(s);
+    xen_pt_register_regions(s, &cmd);
 
     /* reinitialize each config register to be emulated */
     if (xen_pt_config_init(s)) {
@@ -736,6 +739,11 @@ static int xen_pt_initfn(PCIDevice *d)
     }
 
 out:
+    if (cmd) {
+        xen_host_pci_set_word(&s->real_device, PCI_COMMAND,
+                              pci_get_word(d->config + PCI_COMMAND) | cmd);
+    }
+
     memory_listener_register(&s->memory_listener, &address_space_memory);
     memory_listener_register(&s->io_listener, &address_space_io);
     XEN_PT_LOG(d,
--- a/hw/xen/xen_pt_config_init.c
+++ b/hw/xen/xen_pt_config_init.c
@@ -286,23 +286,6 @@ static int xen_pt_irqpin_reg_init(XenPCI
 }
 
 /* Command register */
-static int xen_pt_cmd_reg_read(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
-                               uint16_t *value, uint16_t valid_mask)
-{
-    XenPTRegInfo *reg = cfg_entry->reg;
-    uint16_t valid_emu_mask = 0;
-    uint16_t emu_mask = reg->emu_mask;
-
-    if (s->is_virtfn) {
-        emu_mask |= PCI_COMMAND_MEMORY;
-    }
-
-    /* emulate word register */
-    valid_emu_mask = emu_mask & valid_mask;
-    *value = XEN_PT_MERGE_VALUE(*value, cfg_entry->data, ~valid_emu_mask);
-
-    return 0;
-}
 static int xen_pt_cmd_reg_write(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
                                 uint16_t *val, uint16_t dev_value,
                                 uint16_t valid_mask)
@@ -310,18 +293,13 @@ static int xen_pt_cmd_reg_write(XenPCIPa
     XenPTRegInfo *reg = cfg_entry->reg;
     uint16_t writable_mask = 0;
     uint16_t throughable_mask = 0;
-    uint16_t emu_mask = reg->emu_mask;
-
-    if (s->is_virtfn) {
-        emu_mask |= PCI_COMMAND_MEMORY;
-    }
 
     /* modify emulate register */
     writable_mask = ~reg->ro_mask & valid_mask;
     cfg_entry->data = XEN_PT_MERGE_VALUE(*val, cfg_entry->data, writable_mask);
 
     /* create value for writing to I/O device register */
-    throughable_mask = ~emu_mask & valid_mask;
+    throughable_mask = ~reg->emu_mask & valid_mask;
 
     if (*val & PCI_COMMAND_INTX_DISABLE) {
         throughable_mask |= PCI_COMMAND_INTX_DISABLE;
@@ -605,9 +583,9 @@ static XenPTRegInfo xen_pt_emu_reg_heade
         .size       = 2,
         .init_val   = 0x0000,
         .ro_mask    = 0xF880,
-        .emu_mask   = 0x0740,
+        .emu_mask   = 0x0743,
         .init       = xen_pt_common_reg_init,
-        .u.w.read   = xen_pt_cmd_reg_read,
+        .u.w.read   = xen_pt_word_reg_read,
         .u.w.write  = xen_pt_cmd_reg_write,
     },
     /* Capabilities Pointer reg */


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic