[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [PATCH 7/8] xsm: add checks on PCI configuration access



PCI configuration access is allowed to any privileged domain regardless
of I/O port access restrictions; add XSM hooks for these accesses.

Signed-off-by: Daniel De Graaf <dgdegra@xxxxxxxxxxxxx>
---
 xen/arch/x86/traps.c              |   26 ++++++++++++++++++++++----
 xen/arch/x86/x86_64/mmconfig_64.c |   13 +++++++++++++
 xen/include/xsm/xsm.h             |    6 ++++++
 xen/xsm/dummy.c                   |    8 ++++++++
 xen/xsm/flask/hooks.c             |   24 ++++++++++++++++++++++++
 5 files changed, 73 insertions(+), 4 deletions(-)

diff --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c
index 7f38ddc..2d585c8 100644
--- a/xen/arch/x86/traps.c
+++ b/xen/arch/x86/traps.c
@@ -72,6 +72,7 @@
 #include <asm/mc146818rtc.h>
 #include <asm/hpet.h>
 #include <public/arch-x86/cpuid.h>
+#include <xsm/xsm.h>
 
 /*
  * opt_nmi: one of 'ignore', 'dom0', or 'fatal'.
@@ -1680,6 +1681,21 @@ static int admin_io_okay(
     return ioports_access_permitted(v->domain, port, port + bytes - 1);
 }
 
+static int pci_cfg_ok(struct domain *d, int write, int size)
+{
+    uint32_t machine_bdf;
+    uint16_t start, end;
+    if (!IS_PRIV(d))
+        return 0;
+
+    machine_bdf = (d->arch.pci_cf8 >> 8) & 0xFFFF;
+    start = d->arch.pci_cf8 & 0xFF;
+    end = start + size - 1;
+    if (xsm_pci_config_permission(d, machine_bdf, start, end, write))
+        return 0;
+    return 1;
+}
+
 static uint32_t guest_io_read(
     unsigned int port, unsigned int bytes,
     struct vcpu *v, struct cpu_user_regs *regs)
@@ -1726,12 +1742,13 @@ static uint32_t guest_io_read(
             size = 4;
             sub_data = v->domain->arch.pci_cf8;
         }
-        else if ( ((port & 0xfffc) == 0xcfc) && IS_PRIV(v->domain) )
+        else if ( (port & 0xfffc) == 0xcfc )
         {
             size = min(bytes, 4 - (port & 3));
             if ( size == 3 )
                 size = 2;
-            sub_data = pci_conf_read(v->domain->arch.pci_cf8, port & 3, size);
+            if ( pci_cfg_ok(v->domain, 0, size) )
+                sub_data = pci_conf_read(v->domain->arch.pci_cf8, port & 3, 
size);
         }
 
         if ( size == 4 )
@@ -1798,12 +1815,13 @@ static void guest_io_write(
             size = 4;
             v->domain->arch.pci_cf8 = data;
         }
-        else if ( ((port & 0xfffc) == 0xcfc) && IS_PRIV(v->domain) )
+        else if ( (port & 0xfffc) == 0xcfc )
         {
             size = min(bytes, 4 - (port & 3));
             if ( size == 3 )
                 size = 2;
-            pci_conf_write(v->domain->arch.pci_cf8, port & 3, size, data);
+            if ( pci_cfg_ok(v->domain, 1, size) )
+                pci_conf_write(v->domain->arch.pci_cf8, port & 3, size, data);
         }
 
         if ( size == 4 )
diff --git a/xen/arch/x86/x86_64/mmconfig_64.c 
b/xen/arch/x86/x86_64/mmconfig_64.c
index 16d432e..f2e7fed 100644
--- a/xen/arch/x86/x86_64/mmconfig_64.c
+++ b/xen/arch/x86/x86_64/mmconfig_64.c
@@ -14,6 +14,7 @@
 #include <xen/xmalloc.h>
 #include <xen/pci.h>
 #include <xen/pci_regs.h>
+#include <xsm/xsm.h>
 
 #include "mmconfig.h"
 
@@ -58,6 +59,7 @@ int pci_mmcfg_read(unsigned int seg, unsigned int bus,
               unsigned int devfn, int reg, int len, u32 *value)
 {
     char __iomem *addr;
+    uint32_t mbdf;
 
     /* Why do we have this when nobody checks it. How about a BUG()!? -AK */
     if (unlikely((bus > 255) || (devfn > 255) || (reg > 4095))) {
@@ -65,6 +67,12 @@ err:        *value = -1;
         return -EINVAL;
     }
 
+    mbdf = (seg << 16) | (bus << 8) | devfn;
+    if (xsm_pci_config_permission(current->domain, mbdf, reg, reg + len - 1, 
0)) {
+        *value = -1;
+        return -EPERM;
+    }
+
     addr = pci_dev_base(seg, bus, devfn);
     if (!addr)
         goto err;
@@ -88,11 +96,16 @@ int pci_mmcfg_write(unsigned int seg, unsigned int bus,
                unsigned int devfn, int reg, int len, u32 value)
 {
     char __iomem *addr;
+    uint32_t mbdf;
 
     /* Why do we have this when nobody checks it. How about a BUG()!? -AK */
     if (unlikely((bus > 255) || (devfn > 255) || (reg > 4095)))
         return -EINVAL;
 
+    mbdf = (seg << 16) | (bus << 8) | devfn;
+    if (xsm_pci_config_permission(current->domain, mbdf, reg, reg + len - 1, 
1))
+        return -EPERM;
+
     addr = pci_dev_base(seg, bus, devfn);
     if (!addr)
         return -EINVAL;
diff --git a/xen/include/xsm/xsm.h b/xen/include/xsm/xsm.h
index 0c7f248..df6cec2 100644
--- a/xen/include/xsm/xsm.h
+++ b/xen/include/xsm/xsm.h
@@ -113,6 +113,7 @@ struct xsm_operations {
     int (*schedop_shutdown) (struct domain *d1, struct domain *d2);
     int (*irq_permission) (struct domain *d, int pirq, uint8_t allow);
     int (*iomem_permission) (struct domain *d, uint64_t s, uint64_t e, uint8_t 
allow);
+    int (*pci_config_permission) (struct domain *d, uint32_t machine_bdf, 
uint16_t start, uint16_t end, uint8_t access);
 
     int (*get_device_group) (uint32_t machine_bdf);
     int (*test_assign_device) (uint32_t machine_bdf);
@@ -473,6 +474,11 @@ static inline int xsm_iomem_permission (struct domain *d, 
uint64_t s, uint64_t e
     return xsm_call(iomem_permission(d, s, e, allow));
 }
 
+static inline int xsm_pci_config_permission (struct domain *d, uint32_t 
machine_bdf, uint16_t start, uint16_t end, uint8_t access)
+{
+    return xsm_call(pci_config_permission(d, machine_bdf, start, end, access));
+}
+
 static inline int xsm_get_device_group(uint32_t machine_bdf)
 {
     return xsm_call(get_device_group(machine_bdf));
diff --git a/xen/xsm/dummy.c b/xen/xsm/dummy.c
index a4accb8..4bbfbff 100644
--- a/xen/xsm/dummy.c
+++ b/xen/xsm/dummy.c
@@ -369,6 +369,13 @@ static int dummy_iomem_permission (struct domain *d, 
uint64_t s, uint64_t e, uin
     return 0;
 }
 
+static int dummy_pci_config_permission (struct domain *d, uint32_t machine_bdf,
+                                        uint16_t start, uint16_t end,
+                                        uint8_t access)
+{
+    return 0;
+}
+
 #ifdef CONFIG_X86
 static int dummy_shadow_control (struct domain *d, uint32_t op)
 {
@@ -631,6 +638,7 @@ void xsm_fixup_ops (struct xsm_operations *ops)
 
     set_to_dummy_if_null(ops, irq_permission);
     set_to_dummy_if_null(ops, iomem_permission);
+    set_to_dummy_if_null(ops, pci_config_permission);
 
     set_to_dummy_if_null(ops, test_assign_device);
     set_to_dummy_if_null(ops, assign_device);
diff --git a/xen/xsm/flask/hooks.c b/xen/xsm/flask/hooks.c
index efe52bb..0d35767 100644
--- a/xen/xsm/flask/hooks.c
+++ b/xen/xsm/flask/hooks.c
@@ -762,6 +762,29 @@ static int flask_iomem_permission(struct domain *d, 
uint64_t start, uint64_t end
     return security_iterate_iomem_sids(start, end, _iomem_has_perm, &data);
 }
 
+static int flask_pci_config_permission(struct domain *d, uint32_t machine_bdf, 
uint16_t start, uint16_t end, uint8_t access)
+{
+    u32 rsid;
+    int rc = -EPERM;
+    struct avc_audit_data ad;
+    struct domain_security_struct *ssec;
+    u32 perm = RESOURCE__USE;
+
+    rc = security_device_sid(machine_bdf, &rsid);
+    if ( rc )
+        return rc;
+
+    /* Writes to the BARs count as setup */
+    if ( access && (end >= 0x10 && start < 0x28) )
+        perm = RESOURCE__SETUP;
+
+    AVC_AUDIT_DATA_INIT(&ad, DEV);
+    ad.device = (unsigned long) machine_bdf;
+    ssec = d->ssid;
+    return avc_has_perm(ssec->sid, rsid, SECCLASS_RESOURCE, perm, &ad);
+
+}
+
 static int flask_resource_plug_core(void)
 {
     struct domain_security_struct *ssec;
@@ -1481,6 +1504,7 @@ static struct xsm_operations flask_ops = {
 
     .irq_permission = flask_irq_permission,
     .iomem_permission = flask_iomem_permission,
+    .pci_config_permission = flask_pci_config_permission,
 
     .resource_plug_core = flask_resource_plug_core,
     .resource_unplug_core = flask_resource_unplug_core,
-- 
1.7.7.4


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel


 


Rackspace

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