[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [linux-2.6.18-xen] pciback: limit guest control of command register
# HG changeset patch # User Jan Beulich <jbeulich@xxxxxxxx> # Date 1425992786 -3600 # Node ID a8382d70a4a6205bd0fe67f04717ff32b3ed9605 # Parent 29dd60ae4773da716d26260e19743081c1dd162a pciback: limit guest control of command register Otherwise the guest can abuse that control to cause e.g. PCIe Unsupported Request responses (by disabling memory and/or I/O decoding and subsequently causing [CPU side] accesses to the respective address ranges), which (depending on system configuration) may be fatal to the host. This is CVE-2015-2150 / XSA-120. Signed-off-by: Jan Beulich <jbeulich@xxxxxxxx> Reviewed-by: Konrad Rzeszutek Wilk <konrad.wilk@xxxxxxxxxx> --- diff -r 29dd60ae4773 -r a8382d70a4a6 drivers/xen/pciback/conf_space.c --- a/drivers/xen/pciback/conf_space.c Fri Mar 06 10:54:09 2015 +0100 +++ b/drivers/xen/pciback/conf_space.c Tue Mar 10 14:06:26 2015 +0100 @@ -15,7 +15,7 @@ #include "conf_space.h" #include "conf_space_quirks.h" -static int permissive; +int permissive; module_param(permissive, bool, 0644); #define DEFINE_PCI_CONFIG(op,size,type) \ diff -r 29dd60ae4773 -r a8382d70a4a6 drivers/xen/pciback/conf_space.h --- a/drivers/xen/pciback/conf_space.h Fri Mar 06 10:54:09 2015 +0100 +++ b/drivers/xen/pciback/conf_space.h Tue Mar 10 14:06:26 2015 +0100 @@ -64,6 +64,8 @@ struct config_field_entry { void *data; }; +extern int permissive; + #define OFFSET(cfg_entry) ((cfg_entry)->base_offset+(cfg_entry)->field->offset) /* Add fields to a device - the add_fields macro expects to get a pointer to diff -r 29dd60ae4773 -r a8382d70a4a6 drivers/xen/pciback/conf_space_header.c --- a/drivers/xen/pciback/conf_space_header.c Fri Mar 06 10:54:09 2015 +0100 +++ b/drivers/xen/pciback/conf_space_header.c Tue Mar 10 14:06:26 2015 +0100 @@ -9,6 +9,10 @@ #include "pciback.h" #include "conf_space.h" +struct pci_cmd_info { + u16 val; +}; + struct pci_bar_info { u32 val; u32 len_val; @@ -18,21 +22,35 @@ struct pci_bar_info { #define is_enable_cmd(value) ((value)&(PCI_COMMAND_MEMORY|PCI_COMMAND_IO)) #define is_master_cmd(value) ((value)&PCI_COMMAND_MASTER) +/* Bits guests are allowed to control in permissive mode. */ +#define PCI_COMMAND_GUEST (PCI_COMMAND_MASTER|PCI_COMMAND_SPECIAL| \ + PCI_COMMAND_INVALIDATE|PCI_COMMAND_VGA_PALETTE| \ + PCI_COMMAND_WAIT|PCI_COMMAND_FAST_BACK) + +static void *command_init(struct pci_dev *dev, int offset) +{ + struct pci_cmd_info *cmd = kmalloc(sizeof(*cmd), GFP_KERNEL); + int err; + + if (!cmd) + return ERR_PTR(-ENOMEM); + + err = pci_read_config_word(dev, PCI_COMMAND, &cmd->val); + if (err) { + kfree(cmd); + return ERR_PTR(err); + } + + return cmd; +} + static int command_read(struct pci_dev *dev, int offset, u16 *value, void *data) { - int i; - int ret; + int ret = pci_read_config_word(dev, offset, value); + const struct pci_cmd_info *cmd = data; - ret = pciback_read_config_word(dev, offset, value, data); - if (!dev->is_enabled) - return ret; - - for (i = 0; i < PCI_ROM_RESOURCE; i++) { - if (dev->resource[i].flags & IORESOURCE_IO) - *value |= PCI_COMMAND_IO; - if (dev->resource[i].flags & IORESOURCE_MEM) - *value |= PCI_COMMAND_MEMORY; - } + *value &= PCI_COMMAND_GUEST; + *value |= cmd->val & ~PCI_COMMAND_GUEST; return ret; } @@ -40,6 +58,9 @@ static int command_read(struct pci_dev * static int command_write(struct pci_dev *dev, int offset, u16 value, void *data) { int err; + u16 val; + struct pci_cmd_info *cmd = data; + struct pciback_dev_data *dev_data = pci_get_drvdata(dev); if (!dev->is_enabled && is_enable_cmd(value)) { if (unlikely(verbose_request)) @@ -76,6 +97,18 @@ static int command_write(struct pci_dev } } + cmd->val = value; + + if (!permissive && (!dev_data || !dev_data->permissive)) + return 0; + + /* Only allow the guest to control certain bits. */ + err = pci_read_config_word(dev, offset, &val); + if (err || val == value) + return err; + value &= PCI_COMMAND_GUEST; + value |= val & ~PCI_COMMAND_GUEST; + return pci_write_config_word(dev, offset, value); } @@ -275,6 +308,8 @@ static const struct config_field header_ { .offset = PCI_COMMAND, .size = 2, + .init = command_init, + .release = bar_release, .u.w.read = command_read, .u.w.write = command_write, }, _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |