]> xenbits.xensource.com Git - people/aperard/centos-package-xen.git/commitdiff
Import XSAs 128-131
authorGeorge Dunlap <george.dunlap@eu.citrix.com>
Mon, 1 Jun 2015 10:45:40 +0000 (11:45 +0100)
committerGeorge Dunlap <george.dunlap@eu.citrix.com>
Mon, 1 Jun 2015 10:45:40 +0000 (11:45 +0100)
Signed-off-by: George Dunlap <george.dunlap@eu.citrix.com>
23 files changed:
SOURCES/xsa128-qemut.patch [new file with mode: 0644]
SOURCES/xsa128-qemuu.patch [new file with mode: 0644]
SOURCES/xsa129-qemut.patch [new file with mode: 0644]
SOURCES/xsa129-qemuu.patch [new file with mode: 0644]
SOURCES/xsa130-qemut.patch [new file with mode: 0644]
SOURCES/xsa130-qemuu.patch [new file with mode: 0644]
SOURCES/xsa131-qemut-1.patch [new file with mode: 0644]
SOURCES/xsa131-qemut-2.patch [new file with mode: 0644]
SOURCES/xsa131-qemut-3.patch [new file with mode: 0644]
SOURCES/xsa131-qemut-4.patch [new file with mode: 0644]
SOURCES/xsa131-qemut-5.patch [new file with mode: 0644]
SOURCES/xsa131-qemut-6.patch [new file with mode: 0644]
SOURCES/xsa131-qemut-7.patch [new file with mode: 0644]
SOURCES/xsa131-qemut-8.patch [new file with mode: 0644]
SOURCES/xsa131-qemuu-2.patch [new file with mode: 0644]
SOURCES/xsa131-qemuu-3.patch [new file with mode: 0644]
SOURCES/xsa131-qemuu-4.4-1.patch [new file with mode: 0644]
SOURCES/xsa131-qemuu-4.patch [new file with mode: 0644]
SOURCES/xsa131-qemuu-5.patch [new file with mode: 0644]
SOURCES/xsa131-qemuu-6.patch [new file with mode: 0644]
SOURCES/xsa131-qemuu-7.patch [new file with mode: 0644]
SOURCES/xsa131-qemuu-8.patch [new file with mode: 0644]
SPECS/xen.spec

diff --git a/SOURCES/xsa128-qemut.patch b/SOURCES/xsa128-qemut.patch
new file mode 100644 (file)
index 0000000..7530690
--- /dev/null
@@ -0,0 +1,125 @@
+xen: properly gate host writes of modified PCI CFG contents
+
+The old logic didn't work as intended when an access spanned multiple
+fields (for example a 32-bit access to the location of the MSI Message
+Data field with the high 16 bits not being covered by any known field).
+Remove it and derive which fields not to write to from the accessed
+fields' emulation masks: When they're all ones, there's no point in
+doing any host write.
+
+This fixes a secondary issue at once: We obviously shouldn't make any
+host write attempt when already the host read failed.
+
+This is XSA-128.
+
+Signed-off-by: Jan Beulich <jbeulich@suse.com>
+Reviewed-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
+
+--- a/hw/pass-through.c
++++ b/hw/pass-through.c
+@@ -454,7 +454,7 @@ static struct pt_reg_info_tbl pt_emu_reg
+         .offset     = PCI_INTEL_OPREGION,
+         .size       = 4,
+         .init_val   = 0,
+-        .no_wb      = 1,
++        .emu_mask   = 0xFFFFFFFF,
+         .u.dw.read   = pt_intel_opregion_read,
+         .u.dw.write  = pt_intel_opregion_write,
+         .u.dw.restore  = NULL,
+@@ -657,7 +657,6 @@ static struct pt_reg_info_tbl pt_emu_reg
+         .init_val   = 0x00000000,
+         .ro_mask    = 0x00000003,
+         .emu_mask   = 0xFFFFFFFF,
+-        .no_wb      = 1,
+         .init       = pt_common_reg_init,
+         .u.dw.read  = pt_long_reg_read,
+         .u.dw.write = pt_msgaddr32_reg_write,
+@@ -670,7 +669,6 @@ static struct pt_reg_info_tbl pt_emu_reg
+         .init_val   = 0x00000000,
+         .ro_mask    = 0x00000000,
+         .emu_mask   = 0xFFFFFFFF,
+-        .no_wb      = 1,
+         .init       = pt_msgaddr64_reg_init,
+         .u.dw.read  = pt_long_reg_read,
+         .u.dw.write = pt_msgaddr64_reg_write,
+@@ -683,7 +681,6 @@ static struct pt_reg_info_tbl pt_emu_reg
+         .init_val   = 0x0000,
+         .ro_mask    = 0x0000,
+         .emu_mask   = 0xFFFF,
+-        .no_wb      = 1,
+         .init       = pt_msgdata_reg_init,
+         .u.w.read   = pt_word_reg_read,
+         .u.w.write  = pt_msgdata_reg_write,
+@@ -696,7 +693,6 @@ static struct pt_reg_info_tbl pt_emu_reg
+         .init_val   = 0x0000,
+         .ro_mask    = 0x0000,
+         .emu_mask   = 0xFFFF,
+-        .no_wb      = 1,
+         .init       = pt_msgdata_reg_init,
+         .u.w.read   = pt_word_reg_read,
+         .u.w.write  = pt_msgdata_reg_write,
+@@ -1524,7 +1520,7 @@ 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;
++    uint32_t read_val = 0, wb_mask;
+     uint8_t *ptr_val = NULL;
+     int emul_len = 0;
+     int index = 0;
+@@ -1597,7 +1593,10 @@ static void pt_pci_write_config(PCIDevic
+     {
+         PT_LOG("Error: pci_read_block failed. return value[%d].\n", ret);
+         memset((uint8_t *)&read_val, 0xff, len);
++        wb_mask = 0;
+     }
++    else
++        wb_mask = 0xFFFFFFFF >> ((4 - len) << 3);
+     /* pass directly to libpci for passthrough type register group */
+     if (reg_grp_entry == NULL)
+@@ -1620,6 +1619,11 @@ 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))
++                             << ((len - emul_len) << 3));
++            }
+             /* do emulation depend on register size */
+             switch (reg->size) {
+@@ -1677,8 +1681,19 @@ static void pt_pci_write_config(PCIDevic
+     val >>= ((address & 3) << 3);
+ out:
+-    if (!(reg && reg->no_wb)) {  /* unknown regs are passed through */
+-        ret = pci_write_block(pci_dev, address, (uint8_t *)&val, len);
++    for (index = 0; wb_mask; index += len) {
++        /* unknown regs are passed through */
++        while (!(wb_mask & 0xff)) {
++            index++;
++            wb_mask >>= 8;
++        }
++        len = 0;
++        do {
++            len++;
++            wb_mask >>= 8;
++        } while (wb_mask & 0xff);
++        ret = pci_write_block(pci_dev, address + index,
++                              (uint8_t *)&val + index, len);
+         if (!ret)
+             PT_LOG("Error: pci_write_block failed. return value[%d].\n", ret);
+--- a/hw/pass-through.h
++++ b/hw/pass-through.h
+@@ -372,8 +372,6 @@ struct pt_reg_info_tbl {
+     uint32_t ro_mask;
+     /* reg emulate field mask (ON:emu, OFF:passthrough) */
+     uint32_t emu_mask;
+-    /* no write back allowed */
+-    uint32_t no_wb;
+     /* emul reg initialize method */
+     conf_reg_init init;
+     union {
diff --git a/SOURCES/xsa128-qemuu.patch b/SOURCES/xsa128-qemuu.patch
new file mode 100644 (file)
index 0000000..d551c62
--- /dev/null
@@ -0,0 +1,118 @@
+xen: properly gate host writes of modified PCI CFG contents
+
+The old logic didn't work as intended when an access spanned multiple
+fields (for example a 32-bit access to the location of the MSI Message
+Data field with the high 16 bits not being covered by any known field).
+Remove it and derive which fields not to write to from the accessed
+fields' emulation masks: When they're all ones, there's no point in
+doing any host write.
+
+This fixes a secondary issue at once: We obviously shouldn't make any
+host write attempt when already the host read failed.
+
+This is XSA-128.
+
+Signed-off-by: Jan Beulich <jbeulich@suse.com>
+Reviewed-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
+
+--- a/hw/xen/xen_pt.c
++++ b/hw/xen/xen_pt.c
+@@ -234,7 +234,7 @@ static void xen_pt_pci_write_config(PCID
+     int index = 0;
+     XenPTRegGroup *reg_grp_entry = NULL;
+     int rc = 0;
+-    uint32_t read_val = 0;
++    uint32_t read_val = 0, wb_mask;
+     int emul_len = 0;
+     XenPTReg *reg_entry = NULL;
+     uint32_t find_addr = addr;
+@@ -271,6 +271,9 @@ static void xen_pt_pci_write_config(PCID
+     if (rc < 0) {
+         XEN_PT_ERR(d, "pci_read_block failed. return value: %d.\n", rc);
+         memset(&read_val, 0xff, len);
++        wb_mask = 0;
++    } else {
++        wb_mask = 0xFFFFFFFF >> ((4 - len) << 3);
+     }
+     /* pass directly to the real device for passthrough type register group */
+@@ -298,6 +301,11 @@ static void xen_pt_pci_write_config(PCID
+             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))
++                             << ((len - emul_len) << 3));
++            }
+             /* do emulation based on register size */
+             switch (reg->size) {
+@@ -350,10 +358,19 @@ static void xen_pt_pci_write_config(PCID
+     memory_region_transaction_commit();
+ out:
+-    if (!(reg && reg->no_wb)) {
++    for (index = 0; wb_mask; index += len) {
+         /* unknown regs are passed through */
+-        rc = xen_host_pci_set_block(&s->real_device, addr,
+-                                    (uint8_t *)&val, len);
++        while (!(wb_mask & 0xff)) {
++            index++;
++            wb_mask >>= 8;
++        }
++        len = 0;
++        do {
++            len++;
++            wb_mask >>= 8;
++        } while (wb_mask & 0xff);
++        rc = xen_host_pci_set_block(&s->real_device, addr + index,
++                                    (uint8_t *)&val + index, len);
+         if (rc < 0) {
+             XEN_PT_ERR(d, "pci_write_block failed. return value: %d.\n", rc);
+--- a/hw/xen/xen_pt.h
++++ b/hw/xen/xen_pt.h
+@@ -105,8 +105,6 @@ struct XenPTRegInfo {
+     uint32_t ro_mask;
+     /* reg emulate field mask (ON:emu, OFF:passthrough) */
+     uint32_t emu_mask;
+-    /* no write back allowed */
+-    uint32_t no_wb;
+     xen_pt_conf_reg_init init;
+     /* read/write function pointer
+      * for double_word/word/byte size */
+--- a/hw/xen/xen_pt_config_init.c
++++ b/hw/xen/xen_pt_config_init.c
+@@ -1281,7 +1281,6 @@ static XenPTRegInfo xen_pt_emu_reg_msi[]
+         .init_val   = 0x00000000,
+         .ro_mask    = 0x00000003,
+         .emu_mask   = 0xFFFFFFFF,
+-        .no_wb      = 1,
+         .init       = xen_pt_common_reg_init,
+         .u.dw.read  = xen_pt_long_reg_read,
+         .u.dw.write = xen_pt_msgaddr32_reg_write,
+@@ -1293,7 +1292,6 @@ static XenPTRegInfo xen_pt_emu_reg_msi[]
+         .init_val   = 0x00000000,
+         .ro_mask    = 0x00000000,
+         .emu_mask   = 0xFFFFFFFF,
+-        .no_wb      = 1,
+         .init       = xen_pt_msgaddr64_reg_init,
+         .u.dw.read  = xen_pt_long_reg_read,
+         .u.dw.write = xen_pt_msgaddr64_reg_write,
+@@ -1305,7 +1303,6 @@ static XenPTRegInfo xen_pt_emu_reg_msi[]
+         .init_val   = 0x0000,
+         .ro_mask    = 0x0000,
+         .emu_mask   = 0xFFFF,
+-        .no_wb      = 1,
+         .init       = xen_pt_msgdata_reg_init,
+         .u.w.read   = xen_pt_word_reg_read,
+         .u.w.write  = xen_pt_msgdata_reg_write,
+@@ -1317,7 +1314,6 @@ static XenPTRegInfo xen_pt_emu_reg_msi[]
+         .init_val   = 0x0000,
+         .ro_mask    = 0x0000,
+         .emu_mask   = 0xFFFF,
+-        .no_wb      = 1,
+         .init       = xen_pt_msgdata_reg_init,
+         .u.w.read   = xen_pt_word_reg_read,
+         .u.w.write  = xen_pt_msgdata_reg_write,
diff --git a/SOURCES/xsa129-qemut.patch b/SOURCES/xsa129-qemut.patch
new file mode 100644 (file)
index 0000000..005efa5
--- /dev/null
@@ -0,0 +1,142 @@
+xen: don't allow guest to control MSI mask register
+
+It's being used by the hypervisor. For now simply mimic a device not
+capable of masking, and fully emulate any accesses a guest may issue
+nevertheless as simple reads/writes without side effects.
+
+This is XSA-129.
+
+Signed-off-by: Jan Beulich <jbeulich@suse.com>
+Reviewed-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
+
+--- a/hw/pass-through.c
++++ b/hw/pass-through.c
+@@ -147,6 +147,10 @@ static uint32_t pt_msgaddr64_reg_init(st
+     struct pt_reg_info_tbl *reg, uint32_t real_offset);
+ static uint32_t pt_msgdata_reg_init(struct pt_dev *ptdev,
+     struct pt_reg_info_tbl *reg, uint32_t real_offset);
++static uint32_t pt_mask_reg_init(struct pt_dev *ptdev,
++    struct pt_reg_info_tbl *reg, uint32_t real_offset);
++static uint32_t pt_pending_reg_init(struct pt_dev *ptdev,
++    struct pt_reg_info_tbl *reg, uint32_t real_offset);
+ static uint32_t pt_msixctrl_reg_init(struct pt_dev *ptdev,
+     struct pt_reg_info_tbl *reg, uint32_t real_offset);
+ static uint32_t pt_header_type_reg_init(struct pt_dev *ptdev,
+@@ -644,7 +648,7 @@ static struct pt_reg_info_tbl pt_emu_reg
+         .size       = 2,
+         .init_val   = 0x0000,
+         .ro_mask    = 0xFF8E,
+-        .emu_mask   = 0x007F,
++        .emu_mask   = 0x017F,
+         .init       = pt_msgctrl_reg_init,
+         .u.w.read   = pt_word_reg_read,
+         .u.w.write  = pt_msgctrl_reg_write,
+@@ -698,6 +702,50 @@ static struct pt_reg_info_tbl pt_emu_reg
+         .u.w.write  = pt_msgdata_reg_write,
+         .u.w.restore  = NULL,
+     },
++    /* Mask reg (if PCI_MSI_FLAGS_MASK_BIT set, for 32-bit devices) */
++    {
++        .offset     = PCI_MSI_MASK_32,
++        .size       = 4,
++        .init_val   = 0x00000000,
++        .ro_mask    = 0xFFFFFFFF,
++        .emu_mask   = 0xFFFFFFFF,
++        .init       = pt_mask_reg_init,
++        .u.dw.read  = pt_long_reg_read,
++        .u.dw.write = pt_long_reg_write,
++    },
++    /* Mask reg (if PCI_MSI_FLAGS_MASK_BIT set, for 64-bit devices) */
++    {
++        .offset     = PCI_MSI_MASK_64,
++        .size       = 4,
++        .init_val   = 0x00000000,
++        .ro_mask    = 0xFFFFFFFF,
++        .emu_mask   = 0xFFFFFFFF,
++        .init       = pt_mask_reg_init,
++        .u.dw.read  = pt_long_reg_read,
++        .u.dw.write = pt_long_reg_write,
++    },
++    /* Pending reg (if PCI_MSI_FLAGS_MASK_BIT set, for 32-bit devices) */
++    {
++        .offset     = PCI_MSI_MASK_32 + 4,
++        .size       = 4,
++        .init_val   = 0x00000000,
++        .ro_mask    = 0xFFFFFFFF,
++        .emu_mask   = 0x00000000,
++        .init       = pt_pending_reg_init,
++        .u.dw.read  = pt_long_reg_read,
++        .u.dw.write = pt_long_reg_write,
++    },
++    /* Pending reg (if PCI_MSI_FLAGS_MASK_BIT set, for 64-bit devices) */
++    {
++        .offset     = PCI_MSI_MASK_64 + 4,
++        .size       = 4,
++        .init_val   = 0x00000000,
++        .ro_mask    = 0xFFFFFFFF,
++        .emu_mask   = 0x00000000,
++        .init       = pt_pending_reg_init,
++        .u.dw.read  = pt_long_reg_read,
++        .u.dw.write = pt_long_reg_write,
++    },
+     {
+         .size = 0,
+     },
+@@ -3023,6 +3071,42 @@ static uint32_t pt_msgdata_reg_init(stru
+         return PT_INVALID_REG;
+ }
++/* this function will be called twice (for 32 bit and 64 bit type) */
++/* initialize Mask register */
++static uint32_t pt_mask_reg_init(struct pt_dev *ptdev,
++        struct pt_reg_info_tbl *reg, uint32_t real_offset)
++{
++    uint32_t flags = ptdev->msi->flags;
++    uint32_t offset = reg->offset;
++
++    if (!(flags & PCI_MSI_FLAGS_MASK_BIT))
++        return PT_INVALID_REG;
++
++    if (offset == (flags & PCI_MSI_FLAGS_64BIT ?
++                   PCI_MSI_MASK_64 : PCI_MSI_MASK_32))
++        return reg->init_val;
++
++    return PT_INVALID_REG;
++}
++
++/* this function will be called twice (for 32 bit and 64 bit type) */
++/* initialize Pending register */
++static uint32_t pt_pending_reg_init(struct pt_dev *ptdev,
++        struct pt_reg_info_tbl *reg, uint32_t real_offset)
++{
++    uint32_t flags = ptdev->msi->flags;
++    uint32_t offset = reg->offset;
++
++    if (!(flags & PCI_MSI_FLAGS_MASK_BIT))
++        return PT_INVALID_REG;
++
++    if (offset == (flags & PCI_MSI_FLAGS_64BIT ?
++                   PCI_MSI_MASK_64 + 4 : PCI_MSI_MASK_32 + 4))
++        return reg->init_val;
++
++    return PT_INVALID_REG;
++}
++
+ /* initialize Message Control register for MSI-X */
+ static uint32_t pt_msixctrl_reg_init(struct pt_dev *ptdev,
+         struct pt_reg_info_tbl *reg, uint32_t real_offset)
+--- a/hw/pass-through.h
++++ b/hw/pass-through.h
+@@ -84,6 +84,12 @@
+ #define PCI_MSI_FLAGS_MASK_BIT  0x0100
+ #endif
++#ifndef PCI_MSI_MASK_32
++/* interrupt masking register */
++#define PCI_MSI_MASK_32     12
++#define PCI_MSI_MASK_64     16
++#endif
++
+ #ifndef PCI_EXP_TYPE_PCIE_BRIDGE
+ /* PCI/PCI-X to PCIE Bridge */
+ #define PCI_EXP_TYPE_PCIE_BRIDGE 0x8
diff --git a/SOURCES/xsa129-qemuu.patch b/SOURCES/xsa129-qemuu.patch
new file mode 100644 (file)
index 0000000..96715a6
--- /dev/null
@@ -0,0 +1,172 @@
+xen: don't allow guest to control MSI mask register
+
+It's being used by the hypervisor. For now simply mimic a device not
+capable of masking, and fully emulate any accesses a guest may issue
+nevertheless as simple reads/writes without side effects.
+
+This is XSA-129.
+
+Signed-off-by: Jan Beulich <jbeulich@suse.com>
+Reviewed-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
+
+--- a/hw/pci/msi.c
++++ b/hw/pci/msi.c
+@@ -21,10 +21,6 @@
+ #include "hw/pci/msi.h"
+ #include "qemu/range.h"
+-/* Eventually those constants should go to Linux pci_regs.h */
+-#define PCI_MSI_PENDING_32      0x10
+-#define PCI_MSI_PENDING_64      0x14
+-
+ /* PCI_MSI_ADDRESS_LO */
+ #define PCI_MSI_ADDRESS_LO_MASK         (~0x3)
+--- a/hw/xen/xen_pt_config_init.c
++++ b/hw/xen/xen_pt_config_init.c
+@@ -1018,13 +1018,9 @@ static XenPTRegInfo xen_pt_emu_reg_pm[] 
+  */
+ /* Helper */
+-static bool xen_pt_msgdata_check_type(uint32_t offset, uint16_t flags)
+-{
+-    /* check the offset whether matches the type or not */
+-    bool is_32 = (offset == PCI_MSI_DATA_32) && !(flags & PCI_MSI_FLAGS_64BIT);
+-    bool is_64 = (offset == PCI_MSI_DATA_64) &&  (flags & PCI_MSI_FLAGS_64BIT);
+-    return is_32 || is_64;
+-}
++#define xen_pt_msi_check_type(offset, flags, what) \
++        ((offset) == ((flags) & PCI_MSI_FLAGS_64BIT ? \
++                      PCI_MSI_##what##_64 : PCI_MSI_##what##_32))
+ /* Message Control register */
+ static int xen_pt_msgctrl_reg_init(XenPCIPassthroughState *s,
+@@ -1136,7 +1132,45 @@ static int xen_pt_msgdata_reg_init(XenPC
+     uint32_t offset = reg->offset;
+     /* check the offset whether matches the type or not */
+-    if (xen_pt_msgdata_check_type(offset, flags)) {
++    if (xen_pt_msi_check_type(offset, flags, DATA)) {
++        *data = reg->init_val;
++    } else {
++        *data = XEN_PT_INVALID_REG;
++    }
++    return 0;
++}
++
++/* this function will be called twice (for 32 bit and 64 bit type) */
++/* initialize Mask register */
++static int xen_pt_mask_reg_init(XenPCIPassthroughState *s,
++                                XenPTRegInfo *reg, uint32_t real_offset,
++                                uint32_t *data)
++{
++    uint32_t flags = s->msi->flags;
++
++    /* check the offset whether matches the type or not */
++    if (!(flags & PCI_MSI_FLAGS_MASKBIT)) {
++        *data = XEN_PT_INVALID_REG;
++    } else if (xen_pt_msi_check_type(reg->offset, flags, MASK)) {
++        *data = reg->init_val;
++    } else {
++        *data = XEN_PT_INVALID_REG;
++    }
++    return 0;
++}
++
++/* this function will be called twice (for 32 bit and 64 bit type) */
++/* initialize Pending register */
++static int xen_pt_pending_reg_init(XenPCIPassthroughState *s,
++                                   XenPTRegInfo *reg, uint32_t real_offset,
++                                   uint32_t *data)
++{
++    uint32_t flags = s->msi->flags;
++
++    /* check the offset whether matches the type or not */
++    if (!(flags & PCI_MSI_FLAGS_MASKBIT)) {
++        *data = XEN_PT_INVALID_REG;
++    } else if (xen_pt_msi_check_type(reg->offset, flags, PENDING)) {
+         *data = reg->init_val;
+     } else {
+         *data = XEN_PT_INVALID_REG;
+@@ -1224,7 +1258,7 @@ static int xen_pt_msgdata_reg_write(XenP
+     uint32_t offset = reg->offset;
+     /* check the offset whether matches the type or not */
+-    if (!xen_pt_msgdata_check_type(offset, msi->flags)) {
++    if (!xen_pt_msi_check_type(offset, msi->flags, DATA)) {
+         /* exit I/O emulator */
+         XEN_PT_ERR(&s->dev, "the offset does not match the 32/64 bit type!\n");
+         return -1;
+@@ -1269,7 +1303,7 @@ static XenPTRegInfo xen_pt_emu_reg_msi[]
+         .size       = 2,
+         .init_val   = 0x0000,
+         .ro_mask    = 0xFF8E,
+-        .emu_mask   = 0x007F,
++        .emu_mask   = 0x017F,
+         .init       = xen_pt_msgctrl_reg_init,
+         .u.w.read   = xen_pt_word_reg_read,
+         .u.w.write  = xen_pt_msgctrl_reg_write,
+@@ -1318,6 +1352,50 @@ static XenPTRegInfo xen_pt_emu_reg_msi[]
+         .u.w.read   = xen_pt_word_reg_read,
+         .u.w.write  = xen_pt_msgdata_reg_write,
+     },
++    /* Mask reg (if PCI_MSI_FLAGS_MASKBIT set, for 32-bit devices) */
++    {
++        .offset     = PCI_MSI_MASK_32,
++        .size       = 4,
++        .init_val   = 0x00000000,
++        .ro_mask    = 0xFFFFFFFF,
++        .emu_mask   = 0xFFFFFFFF,
++        .init       = xen_pt_mask_reg_init,
++        .u.dw.read  = xen_pt_long_reg_read,
++        .u.dw.write = xen_pt_long_reg_write,
++    },
++    /* Mask reg (if PCI_MSI_FLAGS_MASKBIT set, for 64-bit devices) */
++    {
++        .offset     = PCI_MSI_MASK_64,
++        .size       = 4,
++        .init_val   = 0x00000000,
++        .ro_mask    = 0xFFFFFFFF,
++        .emu_mask   = 0xFFFFFFFF,
++        .init       = xen_pt_mask_reg_init,
++        .u.dw.read  = xen_pt_long_reg_read,
++        .u.dw.write = xen_pt_long_reg_write,
++    },
++    /* Pending reg (if PCI_MSI_FLAGS_MASKBIT set, for 32-bit devices) */
++    {
++        .offset     = PCI_MSI_MASK_32 + 4,
++        .size       = 4,
++        .init_val   = 0x00000000,
++        .ro_mask    = 0xFFFFFFFF,
++        .emu_mask   = 0x00000000,
++        .init       = xen_pt_pending_reg_init,
++        .u.dw.read  = xen_pt_long_reg_read,
++        .u.dw.write = xen_pt_long_reg_write,
++    },
++    /* Pending reg (if PCI_MSI_FLAGS_MASKBIT set, for 64-bit devices) */
++    {
++        .offset     = PCI_MSI_MASK_64 + 4,
++        .size       = 4,
++        .init_val   = 0x00000000,
++        .ro_mask    = 0xFFFFFFFF,
++        .emu_mask   = 0x00000000,
++        .init       = xen_pt_pending_reg_init,
++        .u.dw.read  = xen_pt_long_reg_read,
++        .u.dw.write = xen_pt_long_reg_write,
++    },
+     {
+         .size = 0,
+     },
+--- a/include/hw/pci/pci_regs.h
++++ b/include/hw/pci/pci_regs.h
+@@ -298,8 +298,10 @@
+ #define PCI_MSI_ADDRESS_HI    8       /* Upper 32 bits (if PCI_MSI_FLAGS_64BIT set) */
+ #define PCI_MSI_DATA_32               8       /* 16 bits of data for 32-bit devices */
+ #define PCI_MSI_MASK_32               12      /* Mask bits register for 32-bit devices */
++#define PCI_MSI_PENDING_32    16      /* Pending bits register for 32-bit devices */
+ #define PCI_MSI_DATA_64               12      /* 16 bits of data for 64-bit devices */
+ #define PCI_MSI_MASK_64               16      /* Mask bits register for 64-bit devices */
++#define PCI_MSI_PENDING_64    20      /* Pending bits register for 32-bit devices */
+ /* MSI-X registers */
+ #define PCI_MSIX_FLAGS                2
diff --git a/SOURCES/xsa130-qemut.patch b/SOURCES/xsa130-qemut.patch
new file mode 100644 (file)
index 0000000..75af778
--- /dev/null
@@ -0,0 +1,21 @@
+xen/MSI-X: disable logging by default
+
+... to avoid allowing the guest to cause the control domain's disk to
+fill.
+
+This is XSA-130.
+
+Signed-off-by: Jan Beulich <jbeulich@suse.com>
+Reviewed-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
+
+--- a/hw/pass-through.h
++++ b/hw/pass-through.h
+@@ -27,7 +27,7 @@
+ #include "qemu-timer.h"
+ /* Log acesss */
+-#define PT_LOGGING_ENABLED
++/* #define PT_LOGGING_ENABLED */
+ /* Print errors even if logging is disabled */
+ #define PT_ERR(_f, _a...)   fprintf(logfile, "%s: " _f, __func__, ##_a)
diff --git a/SOURCES/xsa130-qemuu.patch b/SOURCES/xsa130-qemuu.patch
new file mode 100644 (file)
index 0000000..c2f35bd
--- /dev/null
@@ -0,0 +1,71 @@
+xen/MSI-X: limit error messages resulting from bad guest behavior
+
+... to avoid allowing the guest to cause the control domain's disk to
+fill.
+
+The first message in pci_msix_write() can simply be deleted, as this
+is indeed bad guest behavior, but such out of bounds writes don't
+really need to be logged.
+
+The second one is more problematic, as there guest behavior may only
+appear to be wrong: For one, the old logic didn't take the mask-all bit
+into account. And then this shouldn't depend on host device state (i.e.
+the host may have masked the entry without the guest having done so).
+Plus these writes shouldn't be dropped even when an entry is unmasked.
+Instead, if they can't be made take effect right away, they should take
+effect on the next unmasking or enabling operation - the specification
+explicitly describes such caching behavior. Until we can validly drop
+the message (implementing such caching/latching behavior), issue the
+message just once per MSI-X table entry.
+
+Note that the log message in pci_msix_read() similar to the one being
+removed here is not an issue: "addr" being of unsigned type, and the
+maximum size of the MSI-X table being 32k, entry_nr simply can't be
+negative and hence the conditonal guarding issuing of the message will
+never be true.
+
+This is XSA-130.
+
+Signed-off-by: Jan Beulich <jbeulich@suse.com>
+Reviewed-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
+
+--- a/hw/xen/xen_pt.h
++++ b/hw/xen/xen_pt.h
+@@ -175,6 +175,7 @@ typedef struct XenPTMSIXEntry {
+     uint32_t data;
+     uint32_t vector_ctrl;
+     bool updated; /* indicate whether MSI ADDR or DATA is updated */
++    bool warned;  /* avoid issuing (bogus) warning more than once */
+ } XenPTMSIXEntry;
+ typedef struct XenPTMSIX {
+     uint32_t ctrl_offset;
+--- a/hw/xen/xen_pt_msi.c
++++ b/hw/xen/xen_pt_msi.c
+@@ -434,11 +434,10 @@ static void pci_msix_write(void *opaque,
+     XenPCIPassthroughState *s = opaque;
+     XenPTMSIX *msix = s->msix;
+     XenPTMSIXEntry *entry;
+-    int entry_nr, offset;
++    unsigned int entry_nr, offset;
+     entry_nr = addr / PCI_MSIX_ENTRY_SIZE;
+-    if (entry_nr < 0 || entry_nr >= msix->total_entries) {
+-        XEN_PT_ERR(&s->dev, "asked MSI-X entry '%i' invalid!\n", entry_nr);
++    if (entry_nr >= msix->total_entries) {
+         return;
+     }
+     entry = &msix->msix_entry[entry_nr];
+@@ -460,8 +459,11 @@ static void pci_msix_write(void *opaque,
+             + PCI_MSIX_ENTRY_VECTOR_CTRL;
+         if (msix->enabled && !(*vec_ctrl & PCI_MSIX_ENTRY_CTRL_MASKBIT)) {
+-            XEN_PT_ERR(&s->dev, "Can't update msix entry %d since MSI-X is"
+-                       " already enabled.\n", entry_nr);
++            if (!entry->warned) {
++                entry->warned = true;
++                XEN_PT_ERR(&s->dev, "Can't update msix entry %d since MSI-X is"
++                           " already enabled.\n", entry_nr);
++            }
+             return;
+         }
diff --git a/SOURCES/xsa131-qemut-1.patch b/SOURCES/xsa131-qemut-1.patch
new file mode 100644 (file)
index 0000000..3bfe236
--- /dev/null
@@ -0,0 +1,60 @@
+xen/MSI: don't open-code pass-through of enable bit modifications
+
+Without this the actual XSA-131 fix would cause the enable bit to not
+get set anymore (due to the write back getting suppressed there based
+on the OR of emu_mask, ro_mask, and res_mask).
+
+Note that the fiddling with the enable bit shouldn't really be done by
+qemu, but making this work right (via libxc and the hypervisor) will
+require more extensive changes, which can be postponed until after the
+security issue got addressed.
+
+This is a preparatory patch for XSA-131.
+
+Signed-off-by: Jan Beulich <jbeulich@suse.com>
+Acked-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
+
+--- a/hw/pass-through.c
++++ b/hw/pass-through.c
+@@ -648,7 +648,7 @@ static struct pt_reg_info_tbl pt_emu_reg
+         .size       = 2,
+         .init_val   = 0x0000,
+         .ro_mask    = 0xFF8E,
+-        .emu_mask   = 0x017F,
++        .emu_mask   = 0x017E,
+         .init       = pt_msgctrl_reg_init,
+         .u.w.read   = pt_word_reg_read,
+         .u.w.write  = pt_msgctrl_reg_write,
+@@ -3901,6 +3901,9 @@ static int pt_msgctrl_reg_write(struct p
+     /* modify emulate register */
+     writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask;
++    /* also emulate MSI_ENABLE bit for MSI-INTx translation */
++    if (ptdev->msi_trans_en)
++        writable_mask |= PCI_MSI_FLAGS_ENABLE & valid_mask;
+     cfg_entry->data = PT_MERGE_VALUE(*value, cfg_entry->data, writable_mask);
+     /* update the msi_info too */
+     ptdev->msi->flags |= cfg_entry->data &
+@@ -3909,6 +3912,9 @@ static int pt_msgctrl_reg_write(struct p
+     /* create value for writing to I/O device register */
+     val = *value;
+     throughable_mask = ~reg->emu_mask & valid_mask;
++    /* don't pass through MSI_ENABLE bit for MSI-INTx translation */
++    if (ptdev->msi_trans_en)
++        throughable_mask &= ~PCI_MSI_FLAGS_ENABLE;
+     *value = PT_MERGE_VALUE(*value, dev_value, throughable_mask);
+     /* update MSI */
+@@ -3952,12 +3958,6 @@ static int pt_msgctrl_reg_write(struct p
+         }
+     }
+-    /* pass through MSI_ENABLE bit when no MSI-INTx translation */
+-    if (!ptdev->msi_trans_en) {
+-        *value &= ~PCI_MSI_FLAGS_ENABLE;
+-        *value |= val & PCI_MSI_FLAGS_ENABLE;
+-    }
+-
+     return 0;
+ }
diff --git a/SOURCES/xsa131-qemut-2.patch b/SOURCES/xsa131-qemut-2.patch
new file mode 100644 (file)
index 0000000..cb2c7b9
--- /dev/null
@@ -0,0 +1,140 @@
+xen/pt: consolidate PM capability emu_mask
+
+There's no point in xen_pt_pmcsr_reg_{read,write}() each ORing
+PCI_PM_CTRL_STATE_MASK and PCI_PM_CTRL_NO_SOFT_RESET into a local
+emu_mask variable - we can have the same effect by setting the field
+descriptor's emu_mask member suitably right away. Note that
+xen_pt_pmcsr_reg_write() is being retained in order to allow later
+patches to be less intrusive.
+
+This is a preparatory patch for XSA-131.
+
+Signed-off-by: Jan Beulich <jbeulich@suse.com>
+Acked-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
+@@ -179,9 +179,6 @@ static int pt_long_reg_read(struct pt_de
+ static int pt_bar_reg_read(struct pt_dev *ptdev,
+     struct pt_reg_tbl *cfg_entry,
+     uint32_t *value, uint32_t valid_mask);
+-static int pt_pmcsr_reg_read(struct pt_dev *ptdev,
+-    struct pt_reg_tbl *cfg_entry,
+-    uint16_t *value, uint16_t valid_mask);
+ static int pt_byte_reg_write(struct pt_dev *ptdev,
+     struct pt_reg_tbl *cfg_entry,
+     uint8_t *value, uint8_t dev_value, uint8_t valid_mask);
+@@ -494,7 +491,7 @@ static struct pt_reg_info_tbl pt_emu_reg
+         .u.w.write  = pt_word_reg_write,
+         .u.w.restore  = NULL,
+     },
+-    /* PCI Power Management Control/Status reg */
++    /* PCI Power Management Control/Status reg (->power_mgmt on) */
+     {
+         .offset     = PCI_PM_CTRL,
+         .size       = 2,
+@@ -502,7 +499,19 @@ static struct pt_reg_info_tbl pt_emu_reg
+         .ro_mask    = 0xE1FC,
+         .emu_mask   = 0x8100,
+         .init       = pt_pmcsr_reg_init,
+-        .u.w.read   = pt_pmcsr_reg_read,
++        .u.w.read   = pt_word_reg_read,
++        .u.w.write  = pt_pmcsr_reg_write,
++        .u.w.restore  = pt_pmcsr_reg_restore,
++    },
++    /* PCI Power Management Control/Status reg (->power_mgmt off) */
++    {
++        .offset     = PCI_PM_CTRL,
++        .size       = 2,
++        .init_val   = 0x0008,
++        .ro_mask    = 0xE1FC,
++        .emu_mask   = 0x810B,
++        .init       = pt_pmcsr_reg_init,
++        .u.w.read   = pt_word_reg_read,
+         .u.w.write  = pt_pmcsr_reg_write,
+         .u.w.restore  = pt_pmcsr_reg_restore,
+     },
+@@ -2919,6 +2928,7 @@ static uint32_t pt_pmc_reg_init(struct p
+     return reg->init_val;
+ }
++/* this function will be called twice (for ->power_mgmt on and off cases) */
+ /* initialize PCI Power Management Control/Status register */
+ static uint32_t pt_pmcsr_reg_init(struct pt_dev *ptdev,
+         struct pt_reg_info_tbl *reg, uint32_t real_offset)
+@@ -2926,8 +2936,23 @@ static uint32_t pt_pmcsr_reg_init(struct
+     PCIDevice *d = &ptdev->dev;
+     uint16_t cap_ver  = 0;
+-    if (!ptdev->power_mgmt)
+-        return reg->init_val;
++    switch (reg->emu_mask & (PCI_PM_CTRL_STATE_MASK |
++                             PCI_PM_CTRL_NO_SOFT_RESET))
++    {
++    case 0:
++        if (!ptdev->power_mgmt)
++            return PT_INVALID_REG;
++        break;
++    case PCI_PM_CTRL_STATE_MASK | PCI_PM_CTRL_NO_SOFT_RESET:
++        if (!ptdev->power_mgmt)
++            return reg->init_val;
++        return PT_INVALID_REG;
++    default:
++        /* exit I/O emulator */
++        PT_LOG("Internal error: Invalid PMCSR emulation mask %04x."
++               " I/O emulator exit.\n", reg->emu_mask);
++        exit(1);
++    }
+     /* check PCI Power Management support version */
+     cap_ver = ptdev->pm_state->pmc_field & PCI_PM_CAP_VER_MASK;
+@@ -3417,24 +3442,6 @@ static int pt_bar_reg_read(struct pt_dev
+ }
+-/* read Power Management Control/Status register */
+-static int pt_pmcsr_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 = reg->emu_mask;
+-
+-    if (!ptdev->power_mgmt)
+-        valid_emu_mask |= PCI_PM_CTRL_STATE_MASK | PCI_PM_CTRL_NO_SOFT_RESET;
+-
+-    valid_emu_mask = valid_emu_mask & valid_mask ;
+-    *value = PT_MERGE_VALUE(*value, cfg_entry->data, ~valid_emu_mask);
+-
+-    return 0;
+-}
+-
+-
+ /* write byte size emulate register */
+ static int pt_byte_reg_write(struct pt_dev *ptdev,
+         struct pt_reg_tbl *cfg_entry,
+@@ -3768,21 +3775,17 @@ static int pt_pmcsr_reg_write(struct pt_
+ {
+     struct pt_reg_info_tbl *reg = cfg_entry->reg;
+     PCIDevice *d = &ptdev->dev;
+-    uint16_t emu_mask = reg->emu_mask;
+     uint16_t writable_mask = 0;
+     uint16_t throughable_mask = 0;
+     struct pt_pm_info *pm_state = ptdev->pm_state;
+     uint16_t read_val = 0;
+-    if (!ptdev->power_mgmt)
+-        emu_mask |= PCI_PM_CTRL_STATE_MASK | PCI_PM_CTRL_NO_SOFT_RESET;
+-
+     /* modify emulate register */
+-    writable_mask = emu_mask & ~reg->ro_mask & valid_mask;
++    writable_mask = reg->emu_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;
+     *value = PT_MERGE_VALUE(*value, dev_value, throughable_mask);
+     if (!ptdev->power_mgmt)
diff --git a/SOURCES/xsa131-qemut-3.patch b/SOURCES/xsa131-qemut-3.patch
new file mode 100644 (file)
index 0000000..a50b239
--- /dev/null
@@ -0,0 +1,22 @@
+xen/pt: correctly handle PM status bit
+
+xen_pt_pmcsr_reg_write() needs an adjustment to deal with the RW1C
+nature of the not passed through bit 15 (PCI_PM_CTRL_PME_STATUS).
+
+This is a preparatory patch for XSA-131.
+
+Signed-off-by: Jan Beulich <jbeulich@suse.com>
+Reviewed-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
+
+--- a/hw/pass-through.c
++++ b/hw/pass-through.c
+@@ -3786,7 +3786,8 @@ static int pt_pmcsr_reg_write(struct pt_
+     /* create value for writing to I/O device register */
+     throughable_mask = ~reg->emu_mask & valid_mask;
+-    *value = PT_MERGE_VALUE(*value, dev_value, throughable_mask);
++    *value = PT_MERGE_VALUE(*value, dev_value & ~PCI_PM_CTRL_PME_STATUS,
++                            throughable_mask);
+     if (!ptdev->power_mgmt)
+         return 0;
diff --git a/SOURCES/xsa131-qemut-4.patch b/SOURCES/xsa131-qemut-4.patch
new file mode 100644 (file)
index 0000000..95a7f51
--- /dev/null
@@ -0,0 +1,266 @@
+xen/pt: split out calculation of throughable mask in PCI config space handling
+
+This is just to avoid having to adjust that calculation later in
+multiple places.
+
+Note that including ->ro_mask in get_throughable_mask()'s calculation
+is only an apparent (i.e. benign) behavioral change: For r/o fields it
+doesn't matter > whether they get passed through - either the same flag
+is also set in emu_mask (then there's no change at all) or the field is
+r/o in hardware (and hence a write won't change it anyway).
+
+This is a preparatory patch for 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
+@@ -3442,6 +3442,15 @@ static int pt_bar_reg_read(struct pt_dev
+ }
++static uint32_t get_throughable_mask(const struct pt_dev *ptdev,
++                                     const struct pt_reg_info_tbl *reg,
++                                     uint32_t valid_mask)
++{
++    uint32_t throughable_mask = ~(reg->emu_mask | reg->ro_mask);
++
++    return throughable_mask & valid_mask;
++}
++
+ /* write byte size emulate register */
+ static int pt_byte_reg_write(struct pt_dev *ptdev,
+         struct pt_reg_tbl *cfg_entry,
+@@ -3449,14 +3458,13 @@ static int pt_byte_reg_write(struct pt_d
+ {
+     struct pt_reg_info_tbl *reg = cfg_entry->reg;
+     uint8_t writable_mask = 0;
+-    uint8_t throughable_mask = 0;
++    uint8_t throughable_mask = get_throughable_mask(ptdev, reg, valid_mask);
+     /* modify emulate register */
+     writable_mask = reg->emu_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 = ~reg->emu_mask & valid_mask;
+     *value = PT_MERGE_VALUE(*value, dev_value, throughable_mask);
+     return 0;
+@@ -3469,14 +3477,13 @@ static int pt_word_reg_write(struct pt_d
+ {
+     struct pt_reg_info_tbl *reg = cfg_entry->reg;
+     uint16_t writable_mask = 0;
+-    uint16_t throughable_mask = 0;
++    uint16_t throughable_mask = get_throughable_mask(ptdev, reg, valid_mask);
+     /* modify emulate register */
+     writable_mask = reg->emu_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 = ~reg->emu_mask & valid_mask;
+     *value = PT_MERGE_VALUE(*value, dev_value, throughable_mask);
+     return 0;
+@@ -3489,14 +3496,13 @@ static int pt_long_reg_write(struct pt_d
+ {
+     struct pt_reg_info_tbl *reg = cfg_entry->reg;
+     uint32_t writable_mask = 0;
+-    uint32_t throughable_mask = 0;
++    uint32_t throughable_mask = get_throughable_mask(ptdev, reg, valid_mask);
+     /* modify emulate register */
+     writable_mask = reg->emu_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 = ~reg->emu_mask & valid_mask;
+     *value = PT_MERGE_VALUE(*value, dev_value, throughable_mask);
+     return 0;
+@@ -3509,7 +3515,7 @@ static int pt_cmd_reg_write(struct pt_de
+ {
+     struct pt_reg_info_tbl *reg = cfg_entry->reg;
+     uint16_t writable_mask = 0;
+-    uint16_t throughable_mask = 0;
++    uint16_t throughable_mask = get_throughable_mask(ptdev, reg, valid_mask);
+     uint16_t wr_value = *value;
+     /* modify emulate register */
+@@ -3517,8 +3523,6 @@ static int pt_cmd_reg_write(struct pt_de
+     cfg_entry->data = PT_MERGE_VALUE(*value, cfg_entry->data, writable_mask);
+     /* create value for writing to I/O device register */
+-    throughable_mask = ~reg->emu_mask & valid_mask;
+-
+     if (*value & PCI_COMMAND_DISABLE_INTx)
+     {
+         if (ptdev->msi_trans_en)
+@@ -3564,7 +3568,6 @@ static int pt_bar_reg_write(struct pt_de
+     PCIDevice *d = (PCIDevice *)&ptdev->dev;
+     PCIIORegion *r;
+     uint32_t writable_mask = 0;
+-    uint32_t throughable_mask = 0;
+     uint32_t bar_emu_mask = 0;
+     uint32_t bar_ro_mask = 0;
+     uint32_t new_addr, last_addr;
+@@ -3691,8 +3694,7 @@ static int pt_bar_reg_write(struct pt_de
+ exit:
+     /* create value for writing to I/O device register */
+-    throughable_mask = ~bar_emu_mask & valid_mask;
+-    *value = PT_MERGE_VALUE(*value, dev_value, throughable_mask);
++    *value = PT_MERGE_VALUE(*value, dev_value, 0);
+     /* After BAR reg update, we need to remap BAR*/
+     reg_grp_entry = pt_find_reg_grp(ptdev, PCI_COMMAND);
+@@ -3719,9 +3721,8 @@ static int pt_exp_rom_bar_reg_write(stru
+     PCIDevice *d = (PCIDevice *)&ptdev->dev;
+     PCIIORegion *r;
+     uint32_t writable_mask = 0;
+-    uint32_t throughable_mask = 0;
++    uint32_t throughable_mask = get_throughable_mask(ptdev, reg, valid_mask);
+     uint32_t r_size = 0;
+-    uint32_t bar_emu_mask = 0;
+     uint32_t bar_ro_mask = 0;
+     r = &d->io_regions[PCI_ROM_SLOT];
+@@ -3731,7 +3732,6 @@ static int pt_exp_rom_bar_reg_write(stru
+     PT_GET_EMUL_SIZE(base->bar_flag, r_size);
+     /* set emulate mask and read-only mask */
+-    bar_emu_mask = reg->emu_mask;
+     bar_ro_mask = (reg->ro_mask | (r_size - 1)) & ~PCI_ROM_ADDRESS_ENABLE;
+     /* modify emulate register */
+@@ -3751,7 +3751,6 @@ static int pt_exp_rom_bar_reg_write(stru
+         r->addr = cfg_entry->data;
+     /* create value for writing to I/O device register */
+-    throughable_mask = ~bar_emu_mask & valid_mask;
+     *value = PT_MERGE_VALUE(*value, dev_value, throughable_mask);
+     /* After BAR reg update, we need to remap BAR*/
+@@ -3776,7 +3775,7 @@ static int pt_pmcsr_reg_write(struct pt_
+     struct pt_reg_info_tbl *reg = cfg_entry->reg;
+     PCIDevice *d = &ptdev->dev;
+     uint16_t writable_mask = 0;
+-    uint16_t throughable_mask = 0;
++    uint16_t throughable_mask = get_throughable_mask(ptdev, reg, valid_mask);
+     struct pt_pm_info *pm_state = ptdev->pm_state;
+     uint16_t read_val = 0;
+@@ -3785,7 +3784,6 @@ static int pt_pmcsr_reg_write(struct pt_
+     cfg_entry->data = PT_MERGE_VALUE(*value, cfg_entry->data, writable_mask);
+     /* create value for writing to I/O device register */
+-    throughable_mask = ~reg->emu_mask & valid_mask;
+     *value = PT_MERGE_VALUE(*value, dev_value & ~PCI_PM_CTRL_PME_STATUS,
+                             throughable_mask);
+@@ -3894,7 +3892,7 @@ static int pt_msgctrl_reg_write(struct p
+ {
+     struct pt_reg_info_tbl *reg = cfg_entry->reg;
+     uint16_t writable_mask = 0;
+-    uint16_t throughable_mask = 0;
++    uint16_t throughable_mask = get_throughable_mask(ptdev, reg, valid_mask);
+     uint16_t old_ctrl = cfg_entry->data;
+     PCIDevice *pd = (PCIDevice *)ptdev;
+     uint16_t val;
+@@ -3906,8 +3904,10 @@ static int pt_msgctrl_reg_write(struct p
+     /* modify emulate register */
+     writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask;
+     /* also emulate MSI_ENABLE bit for MSI-INTx translation */
+-    if (ptdev->msi_trans_en)
++    if (ptdev->msi_trans_en) {
+         writable_mask |= PCI_MSI_FLAGS_ENABLE & valid_mask;
++        throughable_mask &= ~PCI_MSI_FLAGS_ENABLE;
++    }
+     cfg_entry->data = PT_MERGE_VALUE(*value, cfg_entry->data, writable_mask);
+     /* update the msi_info too */
+     ptdev->msi->flags |= cfg_entry->data &
+@@ -3915,10 +3915,6 @@ static int pt_msgctrl_reg_write(struct p
+     /* create value for writing to I/O device register */
+     val = *value;
+-    throughable_mask = ~reg->emu_mask & valid_mask;
+-    /* don't pass through MSI_ENABLE bit for MSI-INTx translation */
+-    if (ptdev->msi_trans_en)
+-        throughable_mask &= ~PCI_MSI_FLAGS_ENABLE;
+     *value = PT_MERGE_VALUE(*value, dev_value, throughable_mask);
+     /* update MSI */
+@@ -3972,7 +3968,6 @@ static int pt_msgaddr32_reg_write(struct
+ {
+     struct pt_reg_info_tbl *reg = cfg_entry->reg;
+     uint32_t writable_mask = 0;
+-    uint32_t throughable_mask = 0;
+     uint32_t old_addr = cfg_entry->data;
+     /* modify emulate register */
+@@ -3982,8 +3977,7 @@ static int pt_msgaddr32_reg_write(struct
+     ptdev->msi->addr_lo = cfg_entry->data;
+     /* create value for writing to I/O device register */
+-    throughable_mask = ~reg->emu_mask & valid_mask;
+-    *value = PT_MERGE_VALUE(*value, dev_value, throughable_mask);
++    *value = PT_MERGE_VALUE(*value, dev_value, 0);
+     /* update MSI */
+     if (cfg_entry->data != old_addr)
+@@ -4002,7 +3996,6 @@ static int pt_msgaddr64_reg_write(struct
+ {
+     struct pt_reg_info_tbl *reg = cfg_entry->reg;
+     uint32_t writable_mask = 0;
+-    uint32_t throughable_mask = 0;
+     uint32_t old_addr = cfg_entry->data;
+     /* check whether the type is 64 bit or not */
+@@ -4020,8 +4013,7 @@ static int pt_msgaddr64_reg_write(struct
+     ptdev->msi->addr_hi = cfg_entry->data;
+     /* create value for writing to I/O device register */
+-    throughable_mask = ~reg->emu_mask & valid_mask;
+-    *value = PT_MERGE_VALUE(*value, dev_value, throughable_mask);
++    *value = PT_MERGE_VALUE(*value, dev_value, 0);
+     /* update MSI */
+     if (cfg_entry->data != old_addr)
+@@ -4041,7 +4033,6 @@ static int pt_msgdata_reg_write(struct p
+ {
+     struct pt_reg_info_tbl *reg = cfg_entry->reg;
+     uint16_t writable_mask = 0;
+-    uint16_t throughable_mask = 0;
+     uint16_t old_data = cfg_entry->data;
+     uint32_t flags = ptdev->msi->flags;
+     uint32_t offset = reg->offset;
+@@ -4062,8 +4053,7 @@ static int pt_msgdata_reg_write(struct p
+     ptdev->msi->data = cfg_entry->data;
+     /* create value for writing to I/O device register */
+-    throughable_mask = ~reg->emu_mask & valid_mask;
+-    *value = PT_MERGE_VALUE(*value, dev_value, throughable_mask);
++    *value = PT_MERGE_VALUE(*value, dev_value, 0);
+     /* update MSI */
+     if (cfg_entry->data != old_data)
+@@ -4082,7 +4072,7 @@ static int pt_msixctrl_reg_write(struct 
+ {
+     struct pt_reg_info_tbl *reg = cfg_entry->reg;
+     uint16_t writable_mask = 0;
+-    uint16_t throughable_mask = 0;
++    uint16_t throughable_mask = get_throughable_mask(ptdev, reg, valid_mask);
+     uint16_t old_ctrl = cfg_entry->data;
+     /* modify emulate register */
+@@ -4090,7 +4080,6 @@ static int pt_msixctrl_reg_write(struct 
+     cfg_entry->data = PT_MERGE_VALUE(*value, cfg_entry->data, writable_mask);
+     /* create value for writing to I/O device register */
+-    throughable_mask = ~reg->emu_mask & valid_mask;
+     *value = PT_MERGE_VALUE(*value, dev_value, throughable_mask);
+     /* update MSI-X */
diff --git a/SOURCES/xsa131-qemut-5.patch b/SOURCES/xsa131-qemut-5.patch
new file mode 100644 (file)
index 0000000..fb5c4d4
--- /dev/null
@@ -0,0 +1,22 @@
+xen/pt: mark all PCIe capability bits read-only
+
+xen_pt_emu_reg_pcie[]'s PCI_EXP_DEVCAP needs to cover all bits as read-
+only to avoid unintended write-back (just a precaution, the field ought
+to be read-only in hardware).
+
+This is a preparatory patch for XSA-131.
+
+Signed-off-by: Jan Beulich <jbeulich@suse.com>
+Reviewed-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
+
+--- a/hw/pass-through.c
++++ b/hw/pass-through.c
+@@ -577,7 +577,7 @@ static struct pt_reg_info_tbl pt_emu_reg
+         .offset     = PCI_EXP_DEVCAP,
+         .size       = 4,
+         .init_val   = 0x00000000,
+-        .ro_mask    = 0x1FFCFFFF,
++        .ro_mask    = 0xFFFFFFFF,
+         .emu_mask   = 0x10000000,
+         .init       = pt_common_reg_init,
+         .u.dw.read  = pt_long_reg_read,
diff --git a/SOURCES/xsa131-qemut-6.patch b/SOURCES/xsa131-qemut-6.patch
new file mode 100644 (file)
index 0000000..02d175d
--- /dev/null
@@ -0,0 +1,85 @@
+xen/pt: mark reserved bits in PCI config space fields
+
+The adjustments are solely to make the subsequent patches work right
+(and hence make the patch set consistent), namely if permissive mode
+(introduced by the last patch) gets used (as both reserved registers
+and reserved fields must be similarly protected from guest access in
+default mode, but the guest should be allowed access to them in
+permissive mode).
+
+This is a preparatory patch for XSA-131.
+
+Signed-off-by: Jan Beulich <jbeulich@suse.com>
+
+--- a/hw/pass-through.c
++++ b/hw/pass-through.c
+@@ -283,7 +283,7 @@ static struct pt_reg_info_tbl pt_emu_reg
+         .offset     = PCI_COMMAND,
+         .size       = 2,
+         .init_val   = 0x0000,
+-        .ro_mask    = 0xF880,
++        .res_mask   = 0xF880,
+         .emu_mask   = 0x0743,
+         .init       = pt_common_reg_init,
+         .u.w.read   = pt_word_reg_read,
+@@ -310,7 +310,8 @@ static struct pt_reg_info_tbl pt_emu_reg
+         .offset     = PCI_STATUS,
+         .size       = 2,
+         .init_val   = 0x0000,
+-        .ro_mask    = 0x06FF,
++        .res_mask   = 0x0007,
++        .ro_mask    = 0x06F8,
+         .emu_mask   = 0x0010,
+         .init       = pt_status_reg_init,
+         .u.w.read   = pt_word_reg_read,
+@@ -496,7 +497,8 @@ static struct pt_reg_info_tbl pt_emu_reg
+         .offset     = PCI_PM_CTRL,
+         .size       = 2,
+         .init_val   = 0x0008,
+-        .ro_mask    = 0xE1FC,
++        .res_mask   = 0x00F0,
++        .ro_mask    = 0xE10C,
+         .emu_mask   = 0x8100,
+         .init       = pt_pmcsr_reg_init,
+         .u.w.read   = pt_word_reg_read,
+@@ -508,7 +510,8 @@ static struct pt_reg_info_tbl pt_emu_reg
+         .offset     = PCI_PM_CTRL,
+         .size       = 2,
+         .init_val   = 0x0008,
+-        .ro_mask    = 0xE1FC,
++        .res_mask   = 0x00F0,
++        .ro_mask    = 0xE10C,
+         .emu_mask   = 0x810B,
+         .init       = pt_pmcsr_reg_init,
+         .u.w.read   = pt_word_reg_read,
+@@ -656,7 +659,8 @@ static struct pt_reg_info_tbl pt_emu_reg
+         .offset     = PCI_MSI_FLAGS, // 2
+         .size       = 2,
+         .init_val   = 0x0000,
+-        .ro_mask    = 0xFF8E,
++        .res_mask   = 0xFE00,
++        .ro_mask    = 0x018E,
+         .emu_mask   = 0x017E,
+         .init       = pt_msgctrl_reg_init,
+         .u.w.read   = pt_word_reg_read,
+@@ -779,7 +783,8 @@ static struct pt_reg_info_tbl pt_emu_reg
+         .offset     = PCI_MSI_FLAGS, // 2
+         .size       = 2,
+         .init_val   = 0x0000,
+-        .ro_mask    = 0x3FFF,
++        .res_mask   = 0x3800,
++        .ro_mask    = 0x07FF,
+         .emu_mask   = 0x0000,
+         .init       = pt_msixctrl_reg_init,
+         .u.w.read   = pt_word_reg_read,
+--- a/hw/pass-through.h
++++ b/hw/pass-through.h
+@@ -376,6 +376,8 @@ struct pt_reg_info_tbl {
+     uint32_t size;
+     /* reg initial value */
+     uint32_t init_val;
++    /* reg reserved field mask (ON:reserved, OFF:defined) */
++    uint32_t res_mask;
+     /* reg read only field mask (ON:RO/ROS, OFF:other) */
+     uint32_t ro_mask;
+     /* reg emulate field mask (ON:emu, OFF:passthrough) */
diff --git a/SOURCES/xsa131-qemut-7.patch b/SOURCES/xsa131-qemut-7.patch
new file mode 100644 (file)
index 0000000..b2430b5
--- /dev/null
@@ -0,0 +1,81 @@
+xen/pt: add a few PCI config space field descriptions
+
+Since the next patch will turn all not explicitly described fields
+read-only by default, those fields that have guest writable bits need
+to be given explicit descriptors.
+
+This is a preparatory patch for XSA-131.
+
+Signed-off-by: Jan Beulich <jbeulich@suse.com>
+
+--- a/hw/pass-through.c
++++ b/hw/pass-through.c
+@@ -538,6 +538,16 @@ static struct pt_reg_info_tbl pt_emu_reg
+         .u.b.restore  = NULL,
+     },
+     {
++        .offset     = PCI_VPD_ADDR,
++        .size       = 2,
++        .ro_mask    = 0x0003,
++        .emu_mask   = 0x0003,
++        .init       = pt_common_reg_init,
++        .u.w.read   = pt_word_reg_read,
++        .u.w.write  = pt_word_reg_write,
++        .u.w.restore = pt_word_reg_restore,
++    },
++    {
+         .size = 0,
+     },
+ };
+@@ -599,6 +609,17 @@ static struct pt_reg_info_tbl pt_emu_reg
+         .u.w.write  = pt_word_reg_write,
+         .u.w.restore  = pt_word_reg_restore,
+     },
++    /* Device Status reg */
++    {
++        .offset     = PCI_EXP_DEVSTA,
++        .size       = 2,
++        .res_mask   = 0xFFC0,
++        .ro_mask    = 0x0030,
++        .init       = pt_common_reg_init,
++        .u.w.read   = pt_word_reg_read,
++        .u.w.write  = pt_word_reg_write,
++        .u.w.restore  = pt_word_reg_restore,
++    },
+     /* Link Control reg */
+     {
+         .offset     = PCI_EXP_LNKCTL,
+@@ -611,6 +632,16 @@ static struct pt_reg_info_tbl pt_emu_reg
+         .u.w.write  = pt_word_reg_write,
+         .u.w.restore  = pt_word_reg_restore,
+     },
++    /* Link Status reg */
++    {
++        .offset     = PCI_EXP_LNKSTA,
++        .size       = 2,
++        .ro_mask    = 0x3FFF,
++        .init       = pt_common_reg_init,
++        .u.w.read   = pt_word_reg_read,
++        .u.w.write  = pt_word_reg_write,
++        .u.w.restore = pt_word_reg_restore,
++    },
+     /* Device Control 2 reg */
+     {
+         .offset     = 0x28,
+--- a/hw/pass-through.h
++++ b/hw/pass-through.h
+@@ -105,6 +105,14 @@
+ #define PCI_EXP_TYPE_ROOT_EC     0xa
+ #endif
++#ifndef PCI_VPD_ADDR
++/* Vital Product Data */
++#define PCI_VPD_ADDR          2       /* Address to access (15 bits!) */
++#define  PCI_VPD_ADDR_MASK    0x7fff  /* Address mask */
++#define  PCI_VPD_ADDR_F               0x8000  /* Write 0, 1 indicates completion */
++#define PCI_VPD_DATA          4       /* 32-bits of data returned here */
++#endif
++
+ #ifndef PCI_ERR_UNCOR_MASK
+ /* Uncorrectable Error Mask */
+ #define PCI_ERR_UNCOR_MASK      8
diff --git a/SOURCES/xsa131-qemut-8.patch b/SOURCES/xsa131-qemut-8.patch
new file mode 100644 (file)
index 0000000..875ae96
--- /dev/null
@@ -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)
diff --git a/SOURCES/xsa131-qemuu-2.patch b/SOURCES/xsa131-qemuu-2.patch
new file mode 100644 (file)
index 0000000..fc547f4
--- /dev/null
@@ -0,0 +1,70 @@
+xen/pt: consolidate PM capability emu_mask
+
+There's no point in xen_pt_pmcsr_reg_{read,write}() each ORing
+PCI_PM_CTRL_STATE_MASK and PCI_PM_CTRL_NO_SOFT_RESET into a local
+emu_mask variable - we can have the same effect by setting the field
+descriptor's emu_mask member suitably right away. Note that
+xen_pt_pmcsr_reg_write() is being retained in order to allow later
+patches to be less intrusive.
+
+This is a preparatory patch for XSA-131.
+
+Signed-off-by: Jan Beulich <jbeulich@suse.com>
+Acked-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
+Acked-by: Ian Campbell <ian.campbell@citrix.com>
+
+--- a/hw/xen/xen_pt_config_init.c
++++ b/hw/xen/xen_pt_config_init.c
+@@ -935,38 +935,21 @@ static XenPTRegInfo xen_pt_emu_reg_pcie[
+  * Power Management Capability
+  */
+-/* read Power Management Control/Status register */
+-static int xen_pt_pmcsr_reg_read(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
+-                                 uint16_t *value, uint16_t valid_mask)
+-{
+-    XenPTRegInfo *reg = cfg_entry->reg;
+-    uint16_t valid_emu_mask = reg->emu_mask;
+-
+-    valid_emu_mask |= PCI_PM_CTRL_STATE_MASK | PCI_PM_CTRL_NO_SOFT_RESET;
+-
+-    valid_emu_mask = valid_emu_mask & valid_mask;
+-    *value = XEN_PT_MERGE_VALUE(*value, cfg_entry->data, ~valid_emu_mask);
+-
+-    return 0;
+-}
+ /* write Power Management Control/Status register */
+ static int xen_pt_pmcsr_reg_write(XenPCIPassthroughState *s,
+                                   XenPTReg *cfg_entry, uint16_t *val,
+                                   uint16_t dev_value, uint16_t valid_mask)
+ {
+     XenPTRegInfo *reg = cfg_entry->reg;
+-    uint16_t emu_mask = reg->emu_mask;
+     uint16_t writable_mask = 0;
+     uint16_t throughable_mask = 0;
+-    emu_mask |= PCI_PM_CTRL_STATE_MASK | PCI_PM_CTRL_NO_SOFT_RESET;
+-
+     /* modify emulate register */
+-    writable_mask = emu_mask & ~reg->ro_mask & valid_mask;
++    writable_mask = reg->emu_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;
+     *val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask);
+     return 0;
+@@ -1002,9 +985,9 @@ static XenPTRegInfo xen_pt_emu_reg_pm[] 
+         .size       = 2,
+         .init_val   = 0x0008,
+         .ro_mask    = 0xE1FC,
+-        .emu_mask   = 0x8100,
++        .emu_mask   = 0x810B,
+         .init       = xen_pt_common_reg_init,
+-        .u.w.read   = xen_pt_pmcsr_reg_read,
++        .u.w.read   = xen_pt_word_reg_read,
+         .u.w.write  = xen_pt_pmcsr_reg_write,
+     },
+     {
diff --git a/SOURCES/xsa131-qemuu-3.patch b/SOURCES/xsa131-qemuu-3.patch
new file mode 100644 (file)
index 0000000..f62a4f8
--- /dev/null
@@ -0,0 +1,22 @@
+xen/pt: correctly handle PM status bit
+
+xen_pt_pmcsr_reg_write() needs an adjustment to deal with the RW1C
+nature of the not passed through bit 15 (PCI_PM_CTRL_PME_STATUS).
+
+This is a preparatory patch for XSA-131.
+
+Signed-off-by: Jan Beulich <jbeulich@suse.com>
+Reviewed-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
+
+--- a/hw/xen/xen_pt_config_init.c
++++ b/hw/xen/xen_pt_config_init.c
+@@ -950,7 +950,8 @@ static int xen_pt_pmcsr_reg_write(XenPCI
+     /* create value for writing to I/O device register */
+     throughable_mask = ~reg->emu_mask & valid_mask;
+-    *val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask);
++    *val = XEN_PT_MERGE_VALUE(*val, dev_value & ~PCI_PM_CTRL_PME_STATUS,
++                              throughable_mask);
+     return 0;
+ }
diff --git a/SOURCES/xsa131-qemuu-4.4-1.patch b/SOURCES/xsa131-qemuu-4.4-1.patch
new file mode 100644 (file)
index 0000000..6a61a45
--- /dev/null
@@ -0,0 +1,60 @@
+xen/MSI: don't open-code pass-through of enable bit modifications
+
+Without this the actual XSA-131 fix would cause the enable bit to not
+get set anymore (due to the write back getting suppressed there based
+on the OR of emu_mask, ro_mask, and res_mask).
+
+Note that the fiddling with the enable bit shouldn't really be done by
+qemu, but making this work right (via libxc and the hypervisor) will
+require more extensive changes, which can be postponed until after the
+security issue got addressed.
+
+This is a preparatory patch for XSA-131.
+
+Signed-off-by: Jan Beulich <jbeulich@suse.com>
+Acked-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
+
+--- a/hw/xen/xen_pt_config_init.c
++++ b/hw/xen/xen_pt_config_init.c
+@@ -1055,7 +1055,6 @@ static int xen_pt_msgctrl_reg_write(XenP
+     XenPTMSI *msi = s->msi;
+     uint16_t writable_mask = 0;
+     uint16_t throughable_mask = 0;
+-    uint16_t raw_val;
+     /* Currently no support for multi-vector */
+     if (*val & PCI_MSI_FLAGS_QSIZE) {
+@@ -1068,12 +1067,11 @@ static int xen_pt_msgctrl_reg_write(XenP
+     msi->flags |= cfg_entry->data & ~PCI_MSI_FLAGS_ENABLE;
+     /* create value for writing to I/O device register */
+-    raw_val = *val;
+     throughable_mask = ~reg->emu_mask & valid_mask;
+     *val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask);
+     /* update MSI */
+-    if (raw_val & PCI_MSI_FLAGS_ENABLE) {
++    if (*val & PCI_MSI_FLAGS_ENABLE) {
+         /* setup MSI pirq for the first time */
+         if (!msi->initialized) {
+             /* Init physical one */
+@@ -1101,10 +1099,6 @@ static int xen_pt_msgctrl_reg_write(XenP
+         msi->flags &= ~PCI_MSI_FLAGS_ENABLE;
+     }
+-    /* pass through MSI_ENABLE bit */
+-    *val &= ~PCI_MSI_FLAGS_ENABLE;
+-    *val |= raw_val & PCI_MSI_FLAGS_ENABLE;
+-
+     return 0;
+ }
+@@ -1303,7 +1297,7 @@ static XenPTRegInfo xen_pt_emu_reg_msi[]
+         .size       = 2,
+         .init_val   = 0x0000,
+         .ro_mask    = 0xFF8E,
+-        .emu_mask   = 0x017F,
++        .emu_mask   = 0x017E,
+         .init       = xen_pt_msgctrl_reg_init,
+         .u.w.read   = xen_pt_word_reg_read,
+         .u.w.write  = xen_pt_msgctrl_reg_write,
diff --git a/SOURCES/xsa131-qemuu-4.patch b/SOURCES/xsa131-qemuu-4.patch
new file mode 100644 (file)
index 0000000..c36669b
--- /dev/null
@@ -0,0 +1,248 @@
+xen/pt: split out calculation of throughable mask in PCI config space handling
+
+This is just to avoid having to adjust that calculation later in
+multiple places.
+
+Note that including ->ro_mask in get_throughable_mask()'s calculation
+is only an apparent (i.e. benign) behavioral change: For r/o fields it
+doesn't matter > whether they get passed through - either the same flag
+is also set in emu_mask (then there's no change at all) or the field is
+r/o in hardware (and hence a write won't change it anyway).
+
+This is a preparatory patch for 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/xen/xen_pt_config_init.c
++++ b/hw/xen/xen_pt_config_init.c
+@@ -95,6 +95,14 @@ XenPTReg *xen_pt_find_reg(XenPTRegGroup 
+     return NULL;
+ }
++static uint32_t get_throughable_mask(const XenPCIPassthroughState *s,
++                                     const XenPTRegInfo *reg,
++                                     uint32_t valid_mask)
++{
++    uint32_t throughable_mask = ~(reg->emu_mask | reg->ro_mask);
++
++    return throughable_mask & valid_mask;
++}
+ /****************
+  * general register functions
+@@ -157,14 +165,13 @@ static int xen_pt_byte_reg_write(XenPCIP
+ {
+     XenPTRegInfo *reg = cfg_entry->reg;
+     uint8_t writable_mask = 0;
+-    uint8_t throughable_mask = 0;
++    uint8_t throughable_mask = get_throughable_mask(s, reg, valid_mask);
+     /* modify emulate register */
+     writable_mask = reg->emu_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 = ~reg->emu_mask & valid_mask;
+     *val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask);
+     return 0;
+@@ -175,14 +182,13 @@ static int xen_pt_word_reg_write(XenPCIP
+ {
+     XenPTRegInfo *reg = cfg_entry->reg;
+     uint16_t writable_mask = 0;
+-    uint16_t throughable_mask = 0;
++    uint16_t throughable_mask = get_throughable_mask(s, reg, valid_mask);
+     /* modify emulate register */
+     writable_mask = reg->emu_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 = ~reg->emu_mask & valid_mask;
+     *val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask);
+     return 0;
+@@ -193,14 +199,13 @@ static int xen_pt_long_reg_write(XenPCIP
+ {
+     XenPTRegInfo *reg = cfg_entry->reg;
+     uint32_t writable_mask = 0;
+-    uint32_t throughable_mask = 0;
++    uint32_t throughable_mask = get_throughable_mask(s, reg, valid_mask);
+     /* modify emulate register */
+     writable_mask = reg->emu_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 = ~reg->emu_mask & valid_mask;
+     *val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask);
+     return 0;
+@@ -292,15 +297,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 throughable_mask = get_throughable_mask(s, reg, valid_mask);
+     /* 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 = ~reg->emu_mask & valid_mask;
+-
+     if (*val & PCI_COMMAND_INTX_DISABLE) {
+         throughable_mask |= PCI_COMMAND_INTX_DISABLE;
+     } else {
+@@ -456,7 +459,6 @@ static int xen_pt_bar_reg_write(XenPCIPa
+     PCIDevice *d = &s->dev;
+     const PCIIORegion *r;
+     uint32_t writable_mask = 0;
+-    uint32_t throughable_mask = 0;
+     uint32_t bar_emu_mask = 0;
+     uint32_t bar_ro_mask = 0;
+     uint32_t r_size = 0;
+@@ -513,8 +515,7 @@ static int xen_pt_bar_reg_write(XenPCIPa
+     }
+     /* create value for writing to I/O device register */
+-    throughable_mask = ~bar_emu_mask & valid_mask;
+-    *val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask);
++    *val = XEN_PT_MERGE_VALUE(*val, dev_value, 0);
+     return 0;
+ }
+@@ -528,9 +529,8 @@ static int xen_pt_exp_rom_bar_reg_write(
+     XenPTRegion *base = NULL;
+     PCIDevice *d = (PCIDevice *)&s->dev;
+     uint32_t writable_mask = 0;
+-    uint32_t throughable_mask = 0;
++    uint32_t throughable_mask = get_throughable_mask(s, reg, valid_mask);
+     pcibus_t r_size = 0;
+-    uint32_t bar_emu_mask = 0;
+     uint32_t bar_ro_mask = 0;
+     r_size = d->io_regions[PCI_ROM_SLOT].size;
+@@ -539,7 +539,6 @@ static int xen_pt_exp_rom_bar_reg_write(
+     r_size = xen_pt_get_emul_size(base->bar_flag, r_size);
+     /* set emulate mask and read-only mask */
+-    bar_emu_mask = reg->emu_mask;
+     bar_ro_mask = (reg->ro_mask | (r_size - 1)) & ~PCI_ROM_ADDRESS_ENABLE;
+     /* modify emulate register */
+@@ -547,7 +546,6 @@ static int xen_pt_exp_rom_bar_reg_write(
+     cfg_entry->data = XEN_PT_MERGE_VALUE(*val, cfg_entry->data, writable_mask);
+     /* create value for writing to I/O device register */
+-    throughable_mask = ~bar_emu_mask & valid_mask;
+     *val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask);
+     return 0;
+@@ -942,14 +940,13 @@ static int xen_pt_pmcsr_reg_write(XenPCI
+ {
+     XenPTRegInfo *reg = cfg_entry->reg;
+     uint16_t writable_mask = 0;
+-    uint16_t throughable_mask = 0;
++    uint16_t throughable_mask = get_throughable_mask(s, reg, valid_mask);
+     /* modify emulate register */
+     writable_mask = reg->emu_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 = ~reg->emu_mask & valid_mask;
+     *val = XEN_PT_MERGE_VALUE(*val, dev_value & ~PCI_PM_CTRL_PME_STATUS,
+                               throughable_mask);
+@@ -1042,7 +1039,7 @@ static int xen_pt_msgctrl_reg_write(XenP
+     XenPTRegInfo *reg = cfg_entry->reg;
+     XenPTMSI *msi = s->msi;
+     uint16_t writable_mask = 0;
+-    uint16_t throughable_mask = 0;
++    uint16_t throughable_mask = get_throughable_mask(s, reg, valid_mask);
+     /* Currently no support for multi-vector */
+     if (*val & PCI_MSI_FLAGS_QSIZE) {
+@@ -1055,7 +1052,6 @@ static int xen_pt_msgctrl_reg_write(XenP
+     msi->flags |= cfg_entry->data & ~PCI_MSI_FLAGS_ENABLE;
+     /* create value for writing to I/O device register */
+-    throughable_mask = ~reg->emu_mask & valid_mask;
+     *val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask);
+     /* update MSI */
+@@ -1171,7 +1167,6 @@ static int xen_pt_msgaddr32_reg_write(Xe
+ {
+     XenPTRegInfo *reg = cfg_entry->reg;
+     uint32_t writable_mask = 0;
+-    uint32_t throughable_mask = 0;
+     uint32_t old_addr = cfg_entry->data;
+     /* modify emulate register */
+@@ -1180,8 +1175,7 @@ static int xen_pt_msgaddr32_reg_write(Xe
+     s->msi->addr_lo = cfg_entry->data;
+     /* create value for writing to I/O device register */
+-    throughable_mask = ~reg->emu_mask & valid_mask;
+-    *val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask);
++    *val = XEN_PT_MERGE_VALUE(*val, dev_value, 0);
+     /* update MSI */
+     if (cfg_entry->data != old_addr) {
+@@ -1199,7 +1193,6 @@ static int xen_pt_msgaddr64_reg_write(Xe
+ {
+     XenPTRegInfo *reg = cfg_entry->reg;
+     uint32_t writable_mask = 0;
+-    uint32_t throughable_mask = 0;
+     uint32_t old_addr = cfg_entry->data;
+     /* check whether the type is 64 bit or not */
+@@ -1216,8 +1209,7 @@ static int xen_pt_msgaddr64_reg_write(Xe
+     s->msi->addr_hi = cfg_entry->data;
+     /* create value for writing to I/O device register */
+-    throughable_mask = ~reg->emu_mask & valid_mask;
+-    *val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask);
++    *val = XEN_PT_MERGE_VALUE(*val, dev_value, 0);
+     /* update MSI */
+     if (cfg_entry->data != old_addr) {
+@@ -1239,7 +1231,6 @@ static int xen_pt_msgdata_reg_write(XenP
+     XenPTRegInfo *reg = cfg_entry->reg;
+     XenPTMSI *msi = s->msi;
+     uint16_t writable_mask = 0;
+-    uint16_t throughable_mask = 0;
+     uint16_t old_data = cfg_entry->data;
+     uint32_t offset = reg->offset;
+@@ -1257,8 +1248,7 @@ static int xen_pt_msgdata_reg_write(XenP
+     msi->data = cfg_entry->data;
+     /* create value for writing to I/O device register */
+-    throughable_mask = ~reg->emu_mask & valid_mask;
+-    *val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask);
++    *val = XEN_PT_MERGE_VALUE(*val, dev_value, 0);
+     /* update MSI */
+     if (cfg_entry->data != old_data) {
+@@ -1420,7 +1410,7 @@ static int xen_pt_msixctrl_reg_write(Xen
+ {
+     XenPTRegInfo *reg = cfg_entry->reg;
+     uint16_t writable_mask = 0;
+-    uint16_t throughable_mask = 0;
++    uint16_t throughable_mask = get_throughable_mask(s, reg, valid_mask);
+     int debug_msix_enabled_old;
+     /* modify emulate register */
+@@ -1428,7 +1418,6 @@ static int xen_pt_msixctrl_reg_write(Xen
+     cfg_entry->data = XEN_PT_MERGE_VALUE(*val, cfg_entry->data, writable_mask);
+     /* create value for writing to I/O device register */
+-    throughable_mask = ~reg->emu_mask & valid_mask;
+     *val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask);
+     /* update MSI-X */
diff --git a/SOURCES/xsa131-qemuu-5.patch b/SOURCES/xsa131-qemuu-5.patch
new file mode 100644 (file)
index 0000000..aed87c6
--- /dev/null
@@ -0,0 +1,22 @@
+xen/pt: mark all PCIe capability bits read-only
+
+xen_pt_emu_reg_pcie[]'s PCI_EXP_DEVCAP needs to cover all bits as read-
+only to avoid unintended write-back (just a precaution, the field ought
+to be read-only in hardware).
+
+This is a preparatory patch for XSA-131.
+
+Signed-off-by: Jan Beulich <jbeulich@suse.com>
+Reviewed-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
+
+--- a/hw/xen/xen_pt_config_init.c
++++ b/hw/xen/xen_pt_config_init.c
+@@ -873,7 +873,7 @@ static XenPTRegInfo xen_pt_emu_reg_pcie[
+         .offset     = PCI_EXP_DEVCAP,
+         .size       = 4,
+         .init_val   = 0x00000000,
+-        .ro_mask    = 0x1FFCFFFF,
++        .ro_mask    = 0xFFFFFFFF,
+         .emu_mask   = 0x10000000,
+         .init       = xen_pt_common_reg_init,
+         .u.dw.read  = xen_pt_long_reg_read,
diff --git a/SOURCES/xsa131-qemuu-6.patch b/SOURCES/xsa131-qemuu-6.patch
new file mode 100644 (file)
index 0000000..98313d0
--- /dev/null
@@ -0,0 +1,75 @@
+xen/pt: mark reserved bits in PCI config space fields
+
+The adjustments are solely to make the subsequent patches work right
+(and hence make the patch set consistent), namely if permissive mode
+(introduced by the last patch) gets used (as both reserved registers
+and reserved fields must be similarly protected from guest access in
+default mode, but the guest should be allowed access to them in
+permissive mode).
+
+This is a preparatory patch for XSA-131.
+
+Signed-off-by: Jan Beulich <jbeulich@suse.com>
+
+--- a/hw/xen/xen_pt.h
++++ b/hw/xen/xen_pt.h
+@@ -101,6 +101,8 @@ struct XenPTRegInfo {
+     uint32_t offset;
+     uint32_t size;
+     uint32_t init_val;
++    /* reg reserved field mask (ON:reserved, OFF:defined) */
++    uint32_t res_mask;
+     /* reg read only field mask (ON:RO/ROS, OFF:other) */
+     uint32_t ro_mask;
+     /* reg emulate field mask (ON:emu, OFF:passthrough) */
+--- a/hw/xen/xen_pt_config_init.c
++++ b/hw/xen/xen_pt_config_init.c
+@@ -580,7 +580,7 @@ static XenPTRegInfo xen_pt_emu_reg_heade
+         .offset     = PCI_COMMAND,
+         .size       = 2,
+         .init_val   = 0x0000,
+-        .ro_mask    = 0xF880,
++        .res_mask   = 0xF880,
+         .emu_mask   = 0x0743,
+         .init       = xen_pt_common_reg_init,
+         .u.w.read   = xen_pt_word_reg_read,
+@@ -605,7 +605,8 @@ static XenPTRegInfo xen_pt_emu_reg_heade
+         .offset     = PCI_STATUS,
+         .size       = 2,
+         .init_val   = 0x0000,
+-        .ro_mask    = 0x06FF,
++        .res_mask   = 0x0007,
++        .ro_mask    = 0x06F8,
+         .emu_mask   = 0x0010,
+         .init       = xen_pt_status_reg_init,
+         .u.w.read   = xen_pt_word_reg_read,
+@@ -982,7 +983,8 @@ static XenPTRegInfo xen_pt_emu_reg_pm[] 
+         .offset     = PCI_PM_CTRL,
+         .size       = 2,
+         .init_val   = 0x0008,
+-        .ro_mask    = 0xE1FC,
++        .res_mask   = 0x00F0,
++        .ro_mask    = 0xE10C,
+         .emu_mask   = 0x810B,
+         .init       = xen_pt_common_reg_init,
+         .u.w.read   = xen_pt_word_reg_read,
+@@ -1278,7 +1280,8 @@ static XenPTRegInfo xen_pt_emu_reg_msi[]
+         .offset     = PCI_MSI_FLAGS,
+         .size       = 2,
+         .init_val   = 0x0000,
+-        .ro_mask    = 0xFF8E,
++        .res_mask   = 0xFE00,
++        .ro_mask    = 0x018E,
+         .emu_mask   = 0x017E,
+         .init       = xen_pt_msgctrl_reg_init,
+         .u.w.read   = xen_pt_word_reg_read,
+@@ -1456,7 +1459,8 @@ static XenPTRegInfo xen_pt_emu_reg_msix[
+         .offset     = PCI_MSI_FLAGS,
+         .size       = 2,
+         .init_val   = 0x0000,
+-        .ro_mask    = 0x3FFF,
++        .res_mask   = 0x3800,
++        .ro_mask    = 0x07FF,
+         .emu_mask   = 0x0000,
+         .init       = xen_pt_msixctrl_reg_init,
+         .u.w.read   = xen_pt_word_reg_read,
diff --git a/SOURCES/xsa131-qemuu-7.patch b/SOURCES/xsa131-qemuu-7.patch
new file mode 100644 (file)
index 0000000..fa27fec
--- /dev/null
@@ -0,0 +1,70 @@
+xen/pt: add a few PCI config space field descriptions
+
+Since the next patch will turn all not explicitly described fields
+read-only by default, those fields that have guest writable bits need
+to be given explicit descriptors.
+
+This is a preparatory patch for XSA-131.
+
+Signed-off-by: Jan Beulich <jbeulich@suse.com>
+---
+Notes:
+- blindly allowing all VPD reads may still be a problem (out of bounds
+  addresses aren't allowed, but the spec doesn't say what the effect
+  would be) ==> also an issue in pciback?
+- Vendor Specific cap regs aren't in the table (will become r/o by
+  default with this change)
+- many PCIe cap regs aren't in the table (will again become r/o)
+- same for PM cap regs at offsets 6 and 7
+
+--- a/hw/xen/xen_pt_config_init.c
++++ b/hw/xen/xen_pt_config_init.c
+@@ -756,6 +756,15 @@ static XenPTRegInfo xen_pt_emu_reg_vpd[]
+         .u.b.write  = xen_pt_byte_reg_write,
+     },
+     {
++        .offset     = PCI_VPD_ADDR,
++        .size       = 2,
++        .ro_mask    = 0x0003,
++        .emu_mask   = 0x0003,
++        .init       = xen_pt_common_reg_init,
++        .u.w.read   = xen_pt_word_reg_read,
++        .u.w.write  = xen_pt_word_reg_write,
++    },
++    {
+         .size = 0,
+     },
+ };
+@@ -891,6 +900,16 @@ static XenPTRegInfo xen_pt_emu_reg_pcie[
+         .u.w.read   = xen_pt_word_reg_read,
+         .u.w.write  = xen_pt_word_reg_write,
+     },
++    /* Device Status reg */
++    {
++        .offset     = PCI_EXP_DEVSTA,
++        .size       = 2,
++        .res_mask   = 0xFFC0,
++        .ro_mask    = 0x0030,
++        .init       = xen_pt_common_reg_init,
++        .u.w.read   = xen_pt_word_reg_read,
++        .u.w.write  = xen_pt_word_reg_write,
++    },
+     /* Link Control reg */
+     {
+         .offset     = PCI_EXP_LNKCTL,
+@@ -902,6 +921,15 @@ static XenPTRegInfo xen_pt_emu_reg_pcie[
+         .u.w.read   = xen_pt_word_reg_read,
+         .u.w.write  = xen_pt_word_reg_write,
+     },
++    /* Link Status reg */
++    {
++        .offset     = PCI_EXP_LNKSTA,
++        .size       = 2,
++        .ro_mask    = 0x3FFF,
++        .init       = xen_pt_common_reg_init,
++        .u.w.read   = xen_pt_word_reg_read,
++        .u.w.write  = xen_pt_word_reg_write,
++    },
+     /* Device Control 2 reg */
+     {
+         .offset     = 0x28,
diff --git a/SOURCES/xsa131-qemuu-8.patch b/SOURCES/xsa131-qemuu-8.patch
new file mode 100644 (file)
index 0000000..9537baf
--- /dev/null
@@ -0,0 +1,122 @@
+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>)
+---
+Notes:
+- What purpose does xen_pt_header_type_reg_init() serve (with .emu_mask
+  being zero)?
+- In the qemu-trad case no equivalent logic to that setting/using
+  direct_pci_{msi_translate,power_mgmt} is being added, as that logic
+  seems broken (setting globals from device 0 xenstore settings).
+
+--- a/hw/xen/xen_pt.c
++++ b/hw/xen/xen_pt.c
+@@ -239,6 +239,7 @@ static void xen_pt_pci_write_config(PCID
+     XenPTReg *reg_entry = NULL;
+     uint32_t find_addr = addr;
+     XenPTRegInfo *reg = NULL;
++    bool wp_flag = false;
+     if (xen_pt_pci_config_access_check(d, addr, len)) {
+         return;
+@@ -280,6 +281,10 @@ static void xen_pt_pci_write_config(PCID
+     /* pass directly to the real device for passthrough type register group */
+     if (reg_grp_entry == NULL) {
++        if (!s->permissive) {
++            wb_mask = 0;
++            wp_flag = true;
++        }
+         goto out;
+     }
+@@ -300,12 +305,15 @@ static void xen_pt_pci_write_config(PCID
+             uint32_t real_offset = reg_grp_entry->base_offset + reg->offset;
+             uint32_t valid_mask = 0xFFFFFFFF >> ((4 - emul_len) << 3);
+             uint8_t *ptr_val = NULL;
++            uint32_t wp_mask = reg->emu_mask | reg->ro_mask;
+             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))
++            if (!s->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));
+             }
+@@ -349,6 +357,16 @@ static void xen_pt_pci_write_config(PCID
+         } else {
+             /* nothing to do with passthrough type register,
+              * continue to find next byte */
++            if (!s->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 = true;
++                }
++            }
+             emul_len--;
+             find_addr++;
+         }
+@@ -360,6 +378,13 @@ static void xen_pt_pci_write_config(PCID
+     memory_region_transaction_commit();
+ out:
++    if (wp_flag && !s->permissive_warned) {
++        s->permissive_warned = true;
++        xen_pt_log(d, "Write-back to unknown field 0x%02x (partially) inhibited (0x%0*x)\n",
++                   addr, len * 2, wb_mask);
++        xen_pt_log(d, "If the device doesn't work, try enabling permissive mode\n");
++        xen_pt_log(d, "(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)) {
+@@ -821,6 +846,7 @@ static void xen_pt_unregister_device(PCI
+ static Property xen_pci_passthrough_properties[] = {
+     DEFINE_PROP_PCI_HOST_DEVADDR("hostaddr", XenPCIPassthroughState, hostaddr),
++    DEFINE_PROP_BOOL("permissive", XenPCIPassthroughState, permissive, false),
+     DEFINE_PROP_END_OF_LIST(),
+ };
+--- a/hw/xen/xen_pt.h
++++ b/hw/xen/xen_pt.h
+@@ -197,6 +197,8 @@ struct XenPCIPassthroughState {
+     PCIHostDeviceAddress hostaddr;
+     bool is_virtfn;
++    bool permissive;
++    bool permissive_warned;
+     XenHostPCIDevice real_device;
+     XenPTRegion bases[PCI_NUM_REGIONS]; /* Access regions */
+     QLIST_HEAD(, XenPTRegGroup) reg_grps;
+--- a/hw/xen/xen_pt_config_init.c
++++ b/hw/xen/xen_pt_config_init.c
+@@ -101,6 +101,10 @@ static uint32_t get_throughable_mask(con
+ {
+     uint32_t throughable_mask = ~(reg->emu_mask | reg->ro_mask);
++    if (!s->permissive) {
++        throughable_mask &= ~reg->res_mask;
++    }
++
+     return throughable_mask & valid_mask;
+ }
index d09e48d54623206557d08fd36379b1b8ab682673..fb619fa77bc8b612d7acd75b450ecf9c83ec0d35 100644 (file)
@@ -19,7 +19,7 @@
 Summary: Xen is a virtual machine monitor
 Name:    xen
 Version: 4.4.2
-Release: 2%{?dist}
+Release: 3%{?dist}
 Group:   Development/Libraries
 License: GPLv2+ and LGPLv2+ and BSD
 URL:     http://xen.org/
@@ -55,10 +55,34 @@ Patch1: xen-queue.am
 Patch1001: xen-centos-disableWerror-blktap25.patch
 Patch1005: xen-centos-blktap25-ctl-ipc-restart.patch
 
-Patch2002: xsa126-qemuu.patch
-Patch2003: xsa126-qemut.patch
-Patch2004: xsa133-qemuu.patch
-Patch2005: xsa133-qemut.patch
+Patch2001: xsa126-qemuu.patch
+Patch2002: xsa128-qemuu.patch
+Patch2003: xsa129-qemuu.patch
+Patch2004: xsa130-qemuu.patch
+Patch2005: xsa131-qemuu-4.4-1.patch
+Patch2006: xsa131-qemuu-2.patch
+Patch2007: xsa131-qemuu-3.patch
+Patch2008: xsa131-qemuu-4.patch
+Patch2009: xsa131-qemuu-5.patch
+Patch2010: xsa131-qemuu-6.patch
+Patch2011: xsa131-qemuu-7.patch
+Patch2012: xsa131-qemuu-8.patch
+Patch2013: xsa133-qemuu.patch
+
+Patch3001: xsa126-qemut.patch
+Patch3002: xsa128-qemut.patch
+Patch3003: xsa129-qemut.patch
+Patch3004: xsa130-qemut.patch
+Patch3005: xsa131-qemut-1.patch
+Patch3006: xsa131-qemut-2.patch
+Patch3007: xsa131-qemut-3.patch
+Patch3008: xsa131-qemut-4.patch
+Patch3009: xsa131-qemut-5.patch
+Patch3010: xsa131-qemut-6.patch
+Patch3011: xsa131-qemut-7.patch
+Patch3012: xsa131-qemut-8.patch
+Patch3013: xsa133-qemut.patch
+
 
 BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root
 BuildRequires: transfig libidn-devel zlib-devel texi2html SDL-devel curl-devel
@@ -233,14 +257,38 @@ popd
 %patch1001 -p1
 %patch1005 -p1
 
+%define _default_patch_fuzz 2
+
 pushd tools/qemu-xen
+%patch2001 -p1
 %patch2002 -p1
+%patch2003 -p1
 %patch2004 -p1
+%patch2005 -p1
+%patch2006 -p1
+%patch2007 -p1
+%patch2008 -p1
+%patch2009 -p1
+%patch2010 -p1
+%patch2011 -p1
+%patch2012 -p1
+%patch2013 -p1
 popd
 
 pushd tools/qemu-xen-traditional
-%patch2003 -p1
-%patch2005 -p1
+%patch3001 -p1
+%patch3002 -p1
+%patch3003 -p1
+%patch3004 -p1
+%patch3005 -p1
+%patch3006 -p1
+%patch3007 -p1
+%patch3008 -p1
+%patch3009 -p1
+%patch3010 -p1
+%patch3011 -p1
+%patch3012 -p1
+%patch3013 -p1
 popd
 
 # stubdom sources
@@ -748,6 +796,9 @@ rm -rf %{buildroot}
 %endif
 
 %changelog
+* Mon Jun  1 2015 George Dunlap <george.dunlap@eu.citrix.com> - 4.4.2-3.el6.centos
+ - Import XSA-128,129.130,131
+
 * Wed May 13 2015 George Dunlap <george.dunlap@eu.citrix.com> - 4.4.2-2.el6.centos
  - Import XSA-133