[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


  • To: xen-changelog@xxxxxxxxxxxxxxxxxxx
  • From: Xen patchbot-linux-2.6.18-xen <patchbot@xxxxxxx>
  • Date: Tue, 10 Mar 2015 13:44:02 +0000
  • Delivery-date: Tue, 10 Mar 2015 13:44:10 +0000
  • List-id: "Change log for Mercurial \(receive only\)" <xen-changelog.lists.xen.org>

# 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


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.