]> xenbits.xensource.com Git - xen.git/commitdiff
xen/arch/x86: complete XSM hooks on irq/pirq mappings
authorDaniel De Graaf <dgdegra@tycho.nsa.gov>
Wed, 23 Jan 2013 09:18:50 +0000 (09:18 +0000)
committerDaniel De Graaf <dgdegra@tycho.nsa.gov>
Wed, 23 Jan 2013 09:18:50 +0000 (09:18 +0000)
Manipulation of a domain's pirq namespace was not fully protected by
XSM hooks because the XSM hooks for IRQs needed a physical IRQ.  Since
this may not apply to HVM domains, a complete solution needs to split
the XSM hook for this operation, using one hook for the PIRQ
manipulation and one for controlling access to the hardware IRQ.

This reworking has the advantage of providing the same MSI data to
remove_irq that is provided to add_irq, allowing the PCI device to be
determined in both functions.  It also eliminates the last callers of
rcu_lock_target_domain_by_id in x86 and common code in preparation for
this function's removal.

Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov>
Committed-by: Keir Fraser <keir@xen.org>
xen/arch/x86/irq.c
xen/arch/x86/physdev.c
xen/include/xsm/dummy.h
xen/include/xsm/xsm.h
xen/xsm/dummy.c
xen/xsm/flask/hooks.c
xen/xsm/flask/policy/access_vectors

index 095c17dbacc7cad7b6ffe5183fdec9643c0b3dc6..068c5a022886c7a7b94343b94c4bae20ba5f55c7 100644 (file)
@@ -1874,7 +1874,7 @@ int map_domain_pirq(
         return 0;
     }
 
-    ret = xsm_map_domain_pirq(XSM_HOOK, d, irq, data);
+    ret = xsm_map_domain_irq(XSM_HOOK, d, irq, data);
     if ( ret )
     {
         dprintk(XENLOG_G_ERR, "dom%d: could not permit access to irq %d mapping to pirq %d\n",
@@ -1978,14 +1978,19 @@ int unmap_domain_pirq(struct domain *d, int pirq)
         goto done;
     }
 
+    desc = irq_to_desc(irq);
+    msi_desc = desc->msi_desc;
+
+    ret = xsm_unmap_domain_irq(XSM_HOOK, d, irq, msi_desc);
+    if ( ret )
+        goto done;
+
     forced_unbind = pirq_guest_force_unbind(d, info);
     if ( forced_unbind )
         dprintk(XENLOG_G_WARNING, "dom%d: forcing unbind of pirq %d\n",
                 d->domain_id, pirq);
 
-    desc = irq_to_desc(irq);
-
-    if ( (msi_desc = desc->msi_desc) != NULL )
+    if ( msi_desc != NULL )
         pci_disable_msi(msi_desc);
 
     spin_lock_irqsave(&desc->lock, flags);
index b45e18ac513a08bd00d69bddb465e8b81a15c86b..d9ed5dfd0c641c79c106b3194b88ab34dcb19e6c 100644 (file)
@@ -105,7 +105,11 @@ int physdev_map_pirq(domid_t domid, int type, int *index, int *pirq_p,
         return physdev_hvm_map_pirq(d, type, index, pirq_p);
     }
 
-    ret = rcu_lock_target_domain_by_id(domid, &d);
+    d = rcu_lock_domain_by_any_id(domid);
+    if ( d == NULL )
+        return -ESRCH;
+
+    ret = xsm_map_domain_pirq(XSM_TARGET, d);
     if ( ret )
         return ret;
 
@@ -218,9 +222,13 @@ int physdev_unmap_pirq(domid_t domid, int pirq)
     struct domain *d;
     int ret;
 
-    ret = rcu_lock_target_domain_by_id(domid, &d);
+    d = rcu_lock_domain_by_any_id(domid);
+    if ( d == NULL )
+        return -ESRCH;
+
+    ret = xsm_unmap_domain_pirq(XSM_TARGET, d);
     if ( ret )
-        return ret;
+        goto free_domain;
 
     if ( is_hvm_domain(d) )
     {
@@ -232,10 +240,6 @@ int physdev_unmap_pirq(domid_t domid, int pirq)
             goto free_domain;
     }
 
-    ret = xsm_unmap_domain_pirq(XSM_TARGET, d, domain_pirq_to_irq(d, pirq));
-    if ( ret )
-        goto free_domain;
-
     spin_lock(&pcidevs_lock);
     spin_lock(&d->event_lock);
     ret = unmap_domain_pirq(d, pirq);
index 870bd675c4cabe8c596f82c970d76abfd6deae1e..19bbe19415b07694fab0d95cd83f3aef7181e8b2 100644 (file)
@@ -405,18 +405,30 @@ static XSM_INLINE char *xsm_show_irq_sid(int irq)
     return NULL;
 }
 
-static XSM_INLINE int xsm_map_domain_pirq(XSM_DEFAULT_ARG struct domain *d, int irq, void *data)
+static XSM_INLINE int xsm_map_domain_pirq(XSM_DEFAULT_ARG struct domain *d)
+{
+    XSM_ASSERT_ACTION(XSM_TARGET);
+    return xsm_default_action(action, current->domain, d);
+}
+
+static XSM_INLINE int xsm_map_domain_irq(XSM_DEFAULT_ARG struct domain *d, int irq, void *data)
 {
     XSM_ASSERT_ACTION(XSM_HOOK);
     return xsm_default_action(action, current->domain, d);
 }
 
-static XSM_INLINE int xsm_unmap_domain_pirq(XSM_DEFAULT_ARG struct domain *d, int irq)
+static XSM_INLINE int xsm_unmap_domain_pirq(XSM_DEFAULT_ARG struct domain *d)
 {
     XSM_ASSERT_ACTION(XSM_TARGET);
     return xsm_default_action(action, current->domain, d);
 }
 
+static XSM_INLINE int xsm_unmap_domain_irq(XSM_DEFAULT_ARG struct domain *d, int irq, void *data)
+{
+    XSM_ASSERT_ACTION(XSM_HOOK);
+    return xsm_default_action(action, current->domain, d);
+}
+
 static XSM_INLINE int xsm_irq_permission(XSM_DEFAULT_ARG struct domain *d, int pirq, uint8_t allow)
 {
     XSM_ASSERT_ACTION(XSM_HOOK);
index 50483440c39aa29447e1b65c8a7df43a33ab3db8..2399da0a6d0aa5d06775c7b6a9efa87a9fb15631 100644 (file)
@@ -101,8 +101,10 @@ struct xsm_operations {
     int (*schedop_shutdown) (struct domain *d1, struct domain *d2);
 
     char *(*show_irq_sid) (int irq);
-    int (*map_domain_pirq) (struct domain *d, int irq, void *data);
-    int (*unmap_domain_pirq) (struct domain *d, int irq);
+    int (*map_domain_pirq) (struct domain *d);
+    int (*map_domain_irq) (struct domain *d, int irq, void *data);
+    int (*unmap_domain_pirq) (struct domain *d);
+    int (*unmap_domain_irq) (struct domain *d, int irq, void *data);
     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 (*iomem_mapping) (struct domain *d, uint64_t s, uint64_t e, uint8_t allow);
@@ -370,14 +372,24 @@ static inline char *xsm_show_irq_sid (int irq)
     return xsm_ops->show_irq_sid(irq);
 }
 
-static inline int xsm_map_domain_pirq (xsm_default_t def, struct domain *d, int irq, void *data)
+static inline int xsm_map_domain_pirq (xsm_default_t def, struct domain *d)
 {
-    return xsm_ops->map_domain_pirq(d, irq, data);
+    return xsm_ops->map_domain_pirq(d);
 }
 
-static inline int xsm_unmap_domain_pirq (xsm_default_t def, struct domain *d, int irq)
+static inline int xsm_map_domain_irq (xsm_default_t def, struct domain *d, int irq, void *data)
 {
-    return xsm_ops->unmap_domain_pirq(d, irq);
+    return xsm_ops->map_domain_irq(d, irq, data);
+}
+
+static inline int xsm_unmap_domain_pirq (xsm_default_t def, struct domain *d)
+{
+    return xsm_ops->unmap_domain_pirq(d);
+}
+
+static inline int xsm_unmap_domain_irq (xsm_default_t def, struct domain *d, int irq, void *data)
+{
+    return xsm_ops->unmap_domain_irq(d, irq, data);
 }
 
 static inline int xsm_irq_permission (xsm_default_t def, struct domain *d, int pirq, uint8_t allow)
index 5031e163a9cd0ab3ac7754f841987f174266b2a4..dcd3e3152636b23c4083564aa2098829ed92408f 100644 (file)
@@ -76,7 +76,9 @@ void xsm_fixup_ops (struct xsm_operations *ops)
 
     set_to_dummy_if_null(ops, show_irq_sid);
     set_to_dummy_if_null(ops, map_domain_pirq);
+    set_to_dummy_if_null(ops, map_domain_irq);
     set_to_dummy_if_null(ops, unmap_domain_pirq);
+    set_to_dummy_if_null(ops, unmap_domain_irq);
     set_to_dummy_if_null(ops, irq_permission);
     set_to_dummy_if_null(ops, iomem_permission);
     set_to_dummy_if_null(ops, iomem_mapping);
index 2a13549045ea3daed11c1d94f0932b2dd51f0db4..58695884ae0517cd525e71390a4ca2fcd3546f4c 100644 (file)
@@ -818,18 +818,18 @@ static char *flask_show_irq_sid (int irq)
     return ctx;
 }
 
-static int flask_map_domain_pirq (struct domain *d, int irq, void *data)
+static int flask_map_domain_pirq (struct domain *d)
+{
+    return current_has_perm(d, SECCLASS_RESOURCE, RESOURCE__ADD);
+}
+
+static int flask_map_domain_irq (struct domain *d, int irq, void *data)
 {
     u32 sid, dsid;
     int rc = -EPERM;
     struct msi_info *msi = data;
     struct avc_audit_data ad;
 
-    rc = current_has_perm(d, SECCLASS_RESOURCE, RESOURCE__ADD);
-
-    if ( rc )
-        return rc;
-
     if ( irq >= nr_static_irqs && msi ) {
         u32 machine_bdf = (msi->seg << 16) | (msi->bus << 8) | msi->devfn;
         AVC_AUDIT_DATA_INIT(&ad, DEV);
@@ -851,22 +851,25 @@ static int flask_map_domain_pirq (struct domain *d, int irq, void *data)
     return rc;
 }
 
-static int flask_unmap_domain_pirq (struct domain *d, int irq)
+static int flask_unmap_domain_pirq (struct domain *d)
+{
+    return current_has_perm(d, SECCLASS_RESOURCE, RESOURCE__REMOVE);
+}
+
+static int flask_unmap_domain_irq (struct domain *d, int irq, void *data)
 {
     u32 sid;
     int rc = -EPERM;
+    struct msi_info *msi = data;
     struct avc_audit_data ad;
 
-    rc = current_has_perm(d, SECCLASS_RESOURCE, RESOURCE__REMOVE);
-    if ( rc )
-        return rc;
-
-    if ( irq < nr_static_irqs ) {
-        rc = get_irq_sid(irq, &sid, &ad);
+    if ( irq >= nr_static_irqs && msi ) {
+        u32 machine_bdf = (msi->seg << 16) | (msi->bus << 8) | msi->devfn;
+        AVC_AUDIT_DATA_INIT(&ad, DEV);
+        ad.device = machine_bdf;
+        rc = security_device_sid(machine_bdf, &sid);
     } else {
-        /* It is currently not possible to check the specific MSI IRQ being
-         * removed, since we do not have the msi_info like map_domain_pirq */
-        return 0;
+        rc = get_irq_sid(irq, &sid, &ad);
     }
     if ( rc )
         return rc;
@@ -1481,7 +1484,9 @@ static struct xsm_operations flask_ops = {
     .show_irq_sid = flask_show_irq_sid,
 
     .map_domain_pirq = flask_map_domain_pirq,
+    .map_domain_irq = flask_map_domain_irq,
     .unmap_domain_pirq = flask_unmap_domain_pirq,
+    .unmap_domain_irq = flask_unmap_domain_irq,
     .irq_permission = flask_irq_permission,
     .iomem_permission = flask_iomem_permission,
     .iomem_mapping = flask_iomem_mapping,
index 2fdaede5e8fee898e321295d07b3c2fca256053e..36cbacfa13a3c00bbca6f354816b53697adf2db1 100644 (file)
@@ -368,12 +368,11 @@ class resource
 #  target = resource's security label
 # also checked when using some core Xen devices (target xen_t)
     use
-# PHYSDEVOP_map_pirq and ioapic writes for dom0
+# PHYSDEVOP_map_pirq and ioapic writes for dom0, when acting on real IRQs
 #  For GSI interrupts, the IRQ's label is indexed by the IRQ number
 #  For MSI interrupts, the label of the PCI device is used
     add_irq
-# PHYSDEVOP_unmap_pirq:
-#  This is currently only checked for GSI interrupts
+# PHYSDEVOP_unmap_pirq (same as map, and only for real IRQs)
     remove_irq
 # XEN_DOMCTL_ioport_permission, XEN_DOMCTL_ioport_mapping
     add_ioport