Commit 7611dae8 authored by Jan Beulich's avatar Jan Beulich Committed by Stefano Stabellini
Browse files

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: default avatarJan Beulich <jbeulich@suse.com>
Reviewed-by: default avatarStefano Stabellini <stefano.stabellini@eu.citrix.com>
parent 5c83b2f5
Loading
Loading
Loading
Loading
+0 −4
Original line number Diff line number Diff line
@@ -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)

+88 −10
Original line number Diff line number Diff line
@@ -1016,13 +1016,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,
@@ -1134,7 +1130,45 @@ static int xen_pt_msgdata_reg_init(XenPCIPassthroughState *s,
    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;
@@ -1222,7 +1256,7 @@ static int xen_pt_msgdata_reg_write(XenPCIPassthroughState *s,
    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;
@@ -1267,7 +1301,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,
@@ -1316,6 +1350,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,
    },
+2 −0
Original line number Diff line number Diff line
@@ -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