|
[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 |