summaryrefslogtreecommitdiff
path: root/sysutils/xen-tools/files/xsa131-qemut-8.patch
diff options
context:
space:
mode:
Diffstat (limited to 'sysutils/xen-tools/files/xsa131-qemut-8.patch')
-rw-r--r--sysutils/xen-tools/files/xsa131-qemut-8.patch139
1 files changed, 139 insertions, 0 deletions
diff --git a/sysutils/xen-tools/files/xsa131-qemut-8.patch b/sysutils/xen-tools/files/xsa131-qemut-8.patch
new file mode 100644
index 000000000000..875ae9646f56
--- /dev/null
+++ b/sysutils/xen-tools/files/xsa131-qemut-8.patch
@@ -0,0 +1,139 @@
+xen/pt: unknown PCI config space fields should be read-only
+
+... by default. Add a per-device "permissive" mode similar to pciback's
+to allow restoring previous behavior (and hence break security again,
+i.e. should be used only for trusted guests).
+
+This is part of XSA-131.
+
+Signed-off-by: Jan Beulich <jbeulich@suse.com>
+Acked-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
+Reviewed-by: Anthony PERARD <anthony.perard@citrix.com>)
+
+--- a/hw/pass-through.c
++++ b/hw/pass-through.c
+@@ -1613,10 +1613,10 @@ static void pt_pci_write_config(PCIDevic
+ uint32_t find_addr = address;
+ uint32_t real_offset = 0;
+ uint32_t valid_mask = 0xFFFFFFFF;
+- uint32_t read_val = 0, wb_mask;
++ uint32_t read_val = 0, wb_mask, wp_mask;
+ uint8_t *ptr_val = NULL;
+ int emul_len = 0;
+- int index = 0;
++ int index = 0, wp_flag = 0;
+ int ret = 0;
+
+ #ifdef PT_DEBUG_PCI_CONFIG_ACCESS
+@@ -1695,7 +1695,14 @@ static void pt_pci_write_config(PCIDevic
+
+ /* pass directly to libpci for passthrough type register group */
+ if (reg_grp_entry == NULL)
++ {
++ if (!assigned_device->permissive)
++ {
++ wb_mask = 0;
++ wp_flag = 1;
++ }
+ goto out;
++ }
+
+ /* adjust the read and write value to appropriate CFC-CFF window */
+ read_val <<= ((address & 3) << 3);
+@@ -1714,11 +1721,12 @@ static void pt_pci_write_config(PCIDevic
+ valid_mask = (0xFFFFFFFF >> ((4 - emul_len) << 3));
+ valid_mask <<= ((find_addr - real_offset) << 3);
+ ptr_val = ((uint8_t *)&val + (real_offset & 3));
+- if (reg->emu_mask == (0xFFFFFFFF >> ((4 - reg->size) << 3))) {
+- wb_mask &= ~((reg->emu_mask
+- >> ((find_addr - real_offset) << 3))
++ wp_mask = reg->emu_mask | reg->ro_mask;
++ if (!assigned_device->permissive)
++ wp_mask |= reg->res_mask;
++ if (wp_mask == (0xFFFFFFFF >> ((4 - reg->size) << 3)))
++ wb_mask &= ~((wp_mask >> ((find_addr - real_offset) << 3))
+ << ((len - emul_len) << 3));
+- }
+
+ /* do emulation depend on register size */
+ switch (reg->size) {
+@@ -1767,6 +1775,16 @@ static void pt_pci_write_config(PCIDevic
+ /* nothing to do with passthrough type register,
+ * continue to find next byte
+ */
++ if (!assigned_device->permissive)
++ {
++ wb_mask &= ~(0xff << ((len - emul_len) << 3));
++ /* Unused BARs will make it here, but we don't want to issue
++ * warnings for writes to them (bogus writes get dealt with
++ * above).
++ */
++ if (index < 0)
++ wp_flag = 1;
++ }
+ emul_len--;
+ find_addr++;
+ }
+@@ -1776,6 +1794,15 @@ static void pt_pci_write_config(PCIDevic
+ val >>= ((address & 3) << 3);
+
+ out:
++ if (wp_flag && !assigned_device->permissive_warned)
++ {
++ assigned_device->permissive_warned = 1;
++ PT_LOG("Write-back to unknown field 0x%02x (partially) inhibited (0x%0*x)\n",
++ addr, len * 2, wb_mask);
++ PT_LOG("If device %02x:%02x.%o doesn't work, try enabling permissive\n",
++ pci_bus_num(d->bus), PCI_SLOT(d->devfn), PCI_FUNC(d->devfn));
++ PT_LOG("mode (unsafe) and if it helps report the problem to xen-devel\n");
++ }
+ for (index = 0; wb_mask; index += len) {
+ /* unknown regs are passed through */
+ while (!(wb_mask & 0xff)) {
+@@ -3484,6 +3511,9 @@ static uint32_t get_throughable_mask(con
+ {
+ uint32_t throughable_mask = ~(reg->emu_mask | reg->ro_mask);
+
++ if (!ptdev->permissive)
++ throughable_mask &= ~reg->res_mask;
++
+ return throughable_mask & valid_mask;
+ }
+
+@@ -4322,7 +4352,7 @@ static struct pt_dev * register_real_dev
+ uint8_t e_device, e_intx;
+ uint16_t cmd = 0;
+ char *key, *val;
+- int msi_translate, power_mgmt;
++ int msi_translate, power_mgmt, permissive = 0;
+
+ PT_LOG("Assigning real physical device %02x:%02x.%x ...\n",
+ r_bus, r_dev, r_func);
+@@ -4366,6 +4396,8 @@ static struct pt_dev * register_real_dev
+ else
+ PT_LOG("Error: unrecognized value for msitranslate=\n");
+ }
++ else if (strcmp(key, "permissive") == 0)
++ permissive = 1;
+ else if (strcmp(key, "power_mgmt") == 0)
+ {
+ if (strcmp(val, "0") == 0)
+@@ -4403,6 +4435,7 @@ static struct pt_dev * register_real_dev
+ assigned_device->msi_trans_cap = msi_translate;
+ assigned_device->power_mgmt = power_mgmt;
+ assigned_device->is_virtfn = pt_dev_is_virtfn(pci_dev);
++ assigned_device->permissive = permissive;
+ pt_iomul_init(assigned_device, r_bus, r_dev, r_func);
+
+ /* Initialize virtualized PCI configuration (Extended 256 Bytes) */
+--- a/hw/pass-through.h
++++ b/hw/pass-through.h
+@@ -242,6 +242,8 @@ struct pt_dev {
+ unsigned power_mgmt:1;
+ struct pt_pm_info *pm_state; /* PM virtualization */
+ unsigned is_virtfn:1;
++ unsigned permissive:1;
++ unsigned permissive_warned:1;
+
+ /* io port multiplexing */
+ #define PCI_IOMUL_INVALID_FD (-1)