537e0d17a8
The config is now generated based on Fedora's config. This way we need to only track qubes specific changes and can quickly update to never Fedora configs.
186 lines
5.5 KiB
Diff
186 lines
5.5 KiB
Diff
From 292dcb5eb9ceedeb981eb926be566af8c99cbb26 Mon Sep 17 00:00:00 2001
|
|
From: HW42 <hw42@ipsumj.de>
|
|
Date: Tue, 12 Sep 2017 00:49:02 +0200
|
|
Subject: [PATCH] xen-pciback: add attribute to allow MSI enable flag writes
|
|
|
|
QEMU running in a stubdom needs to be able to set the MSI enable flag in
|
|
the PCI config space. This adds an attribute 'allow_msi_enable' which
|
|
when set for a PCI device allows writes to this flag. The toolstack will
|
|
need to set this for stubdoms.
|
|
|
|
This should not introduce any new security issues since a malicious
|
|
guest (or stubdom) can already generate MSIs through other ways, see
|
|
[1] page 8.
|
|
|
|
[1]: https://invisiblethingslab.com/resources/2011/Software%20Attacks%20on%20Intel%20VT-d.pdf
|
|
---
|
|
drivers/xen/xen-pciback/conf_space_capability.c | 39 +++++++++++++++
|
|
drivers/xen/xen-pciback/pci_stub.c | 65 +++++++++++++++++++++++++
|
|
drivers/xen/xen-pciback/pciback.h | 1 +
|
|
3 files changed, 105 insertions(+)
|
|
|
|
--- a/drivers/xen/xen-pciback/conf_space_capability.c
|
|
+++ b/drivers/xen/xen-pciback/conf_space_capability.c
|
|
@@ -190,6 +190,40 @@ static const struct config_field caplist
|
|
{}
|
|
};
|
|
|
|
+#define MSI_OK_BITS (PCI_MSI_FLAGS_ENABLE)
|
|
+
|
|
+static int msi_flags_write(struct pci_dev *dev, int offset, u16 new_value,
|
|
+ void *data)
|
|
+{
|
|
+ int err;
|
|
+ u16 old_value;
|
|
+ struct xen_pcibk_dev_data *dev_data = pci_get_drvdata(dev);
|
|
+
|
|
+ if (xen_pcibk_permissive || dev_data->permissive)
|
|
+ goto write;
|
|
+
|
|
+ err = pci_read_config_word(dev, offset, &old_value);
|
|
+ if (err)
|
|
+ return err;
|
|
+
|
|
+ if (!dev_data->allow_msi_enable
|
|
+ || (new_value ^ old_value) & ~MSI_OK_BITS)
|
|
+ return PCIBIOS_SET_FAILED;
|
|
+
|
|
+write:
|
|
+ return pci_write_config_word(dev, offset, new_value);
|
|
+}
|
|
+
|
|
+static const struct config_field caplist_msi[] = {
|
|
+ {
|
|
+ .offset = PCI_MSI_FLAGS,
|
|
+ .size = 2,
|
|
+ .u.w.read = xen_pcibk_read_config_word,
|
|
+ .u.w.write = msi_flags_write,
|
|
+ },
|
|
+ {}
|
|
+};
|
|
+
|
|
static struct xen_pcibk_config_capability xen_pcibk_config_capability_pm = {
|
|
.capability = PCI_CAP_ID_PM,
|
|
.fields = caplist_pm,
|
|
@@ -198,11 +232,16 @@ static struct xen_pcibk_config_capabilit
|
|
.capability = PCI_CAP_ID_VPD,
|
|
.fields = caplist_vpd,
|
|
};
|
|
+static struct xen_pcibk_config_capability xen_pcibk_config_capability_msi = {
|
|
+ .capability = PCI_CAP_ID_MSI,
|
|
+ .fields = caplist_msi,
|
|
+};
|
|
|
|
int xen_pcibk_config_capability_init(void)
|
|
{
|
|
register_capability(&xen_pcibk_config_capability_vpd);
|
|
register_capability(&xen_pcibk_config_capability_pm);
|
|
+ register_capability(&xen_pcibk_config_capability_msi);
|
|
|
|
return 0;
|
|
}
|
|
--- a/drivers/xen/xen-pciback/pci_stub.c
|
|
+++ b/drivers/xen/xen-pciback/pci_stub.c
|
|
@@ -303,6 +303,8 @@ void pcistub_put_pci_dev(struct pci_dev
|
|
xen_pcibk_config_reset_dev(dev);
|
|
xen_pcibk_config_free_dyn_fields(dev);
|
|
|
|
+ dev_data->allow_msi_enable = 0;
|
|
+
|
|
xen_unregister_device_domain_owner(dev);
|
|
|
|
spin_lock_irqsave(&found_psdev->lock, flags);
|
|
@@ -1430,6 +1432,63 @@ static ssize_t permissive_show(struct de
|
|
}
|
|
static DRIVER_ATTR_RW(permissive);
|
|
|
|
+static ssize_t allow_msi_enable_store(struct device_driver *drv, const char *buf,
|
|
+ size_t count)
|
|
+{
|
|
+ int domain, bus, slot, func;
|
|
+ int err;
|
|
+ struct pcistub_device *psdev;
|
|
+ struct xen_pcibk_dev_data *dev_data;
|
|
+
|
|
+ err = str_to_slot(buf, &domain, &bus, &slot, &func);
|
|
+ if (err)
|
|
+ goto out;
|
|
+
|
|
+ psdev = pcistub_device_find(domain, bus, slot, func);
|
|
+ if (!psdev) {
|
|
+ err = -ENODEV;
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ dev_data = pci_get_drvdata(psdev->dev);
|
|
+ /* the driver data for a device should never be null at this point */
|
|
+ if (!dev_data) {
|
|
+ err = -ENXIO;
|
|
+ goto release;
|
|
+ }
|
|
+ dev_data->allow_msi_enable = 1;
|
|
+release:
|
|
+ pcistub_device_put(psdev);
|
|
+out:
|
|
+ if (!err)
|
|
+ err = count;
|
|
+ return err;
|
|
+}
|
|
+
|
|
+static ssize_t allow_msi_enable_show(struct device_driver *drv, char *buf)
|
|
+{
|
|
+ struct pcistub_device *psdev;
|
|
+ struct xen_pcibk_dev_data *dev_data;
|
|
+ size_t count = 0;
|
|
+ unsigned long flags;
|
|
+ spin_lock_irqsave(&pcistub_devices_lock, flags);
|
|
+ list_for_each_entry(psdev, &pcistub_devices, dev_list) {
|
|
+ if (count >= PAGE_SIZE)
|
|
+ break;
|
|
+ if (!psdev->dev)
|
|
+ continue;
|
|
+ dev_data = pci_get_drvdata(psdev->dev);
|
|
+ if (!dev_data || !dev_data->allow_msi_enable)
|
|
+ continue;
|
|
+ count +=
|
|
+ scnprintf(buf + count, PAGE_SIZE - count, "%s\n",
|
|
+ pci_name(psdev->dev));
|
|
+ }
|
|
+ spin_unlock_irqrestore(&pcistub_devices_lock, flags);
|
|
+ return count;
|
|
+}
|
|
+static DRIVER_ATTR_RW(allow_msi_enable);
|
|
+
|
|
static void pcistub_exit(void)
|
|
{
|
|
driver_remove_file(&xen_pcibk_pci_driver.driver, &driver_attr_new_slot);
|
|
@@ -1440,6 +1499,8 @@ static void pcistub_exit(void)
|
|
driver_remove_file(&xen_pcibk_pci_driver.driver,
|
|
&driver_attr_permissive);
|
|
driver_remove_file(&xen_pcibk_pci_driver.driver,
|
|
+ &driver_attr_allow_msi_enable);
|
|
+ driver_remove_file(&xen_pcibk_pci_driver.driver,
|
|
&driver_attr_irq_handlers);
|
|
driver_remove_file(&xen_pcibk_pci_driver.driver,
|
|
&driver_attr_irq_handler_state);
|
|
@@ -1529,6 +1590,9 @@ static int __init pcistub_init(void)
|
|
if (!err)
|
|
err = driver_create_file(&xen_pcibk_pci_driver.driver,
|
|
&driver_attr_permissive);
|
|
+ if (!err)
|
|
+ err = driver_create_file(&xen_pcibk_pci_driver.driver,
|
|
+ &driver_attr_allow_msi_enable);
|
|
|
|
if (!err)
|
|
err = driver_create_file(&xen_pcibk_pci_driver.driver,
|
|
--- a/drivers/xen/xen-pciback/pciback.h
|
|
+++ b/drivers/xen/xen-pciback/pciback.h
|
|
@@ -45,6 +45,7 @@ struct xen_pcibk_dev_data {
|
|
struct list_head config_fields;
|
|
struct pci_saved_state *pci_saved_state;
|
|
unsigned int permissive:1;
|
|
+ unsigned int allow_msi_enable:1;
|
|
unsigned int warned_on_write:1;
|
|
unsigned int enable_intx:1;
|
|
unsigned int isr_on:1; /* Whether the IRQ handler is installed. */
|