diff options
author | Jan Beulich <jbeulich@suse.com> | 2015-03-31 15:18:03 +0100 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2015-04-09 23:37:21 +0100 |
commit | 81b23ef82cd1be29ca3d69ab7e98b5b5e55926ce (patch) | |
tree | 32abd64c12c5e0b8da5e524da43bad71095bbda2 | |
parent | 6a460ed18a3fda0eb2d9c96b8b01817b4dcbded4 (diff) | |
download | qemu-81b23ef82cd1be29ca3d69ab7e98b5b5e55926ce.zip qemu-81b23ef82cd1be29ca3d69ab7e98b5b5e55926ce.tar.gz qemu-81b23ef82cd1be29ca3d69ab7e98b5b5e55926ce.tar.bz2 |
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>
Message-id: alpine.DEB.2.02.1503311510300.7690@kaball.uk.xensource.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r-- | hw/xen/xen_pt.c | 12 | ||||
-rw-r--r-- | hw/xen/xen_pt_config_init.c | 28 |
2 files changed, 13 insertions, 27 deletions
diff --git a/hw/xen/xen_pt.c b/hw/xen/xen_pt.c index f2893b2..d095c08 100644 --- 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(XenPCIPassthroughState *s) 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(XenPCIPassthroughState *s) 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, &s->dev.bus_master_as); memory_listener_register(&s->io_listener, &address_space_io); XEN_PT_LOG(d, diff --git a/hw/xen/xen_pt_config_init.c b/hw/xen/xen_pt_config_init.c index d99c22e..95a51db 100644 --- 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(XenPCIPassthroughState *s, } /* 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(XenPCIPassthroughState *s, XenPTReg *cfg_entry, 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; @@ -603,9 +581,9 @@ static XenPTRegInfo xen_pt_emu_reg_header0[] = { .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 */ |