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

[xen staging-4.17] domain: locking for irq_caps accesses



commit 0a5149863d711e1af964f858f2f089bd25a5f541
Author:     Jan Beulich <jbeulich@xxxxxxxx>
AuthorDate: Thu Jun 4 21:42:55 2026 +0100
Commit:     Andrew Cooper <andrew.cooper3@xxxxxxxxxx>
CommitDate: Thu Jun 4 22:29:12 2026 +0100

    domain: locking for irq_caps accesses
    
    In order to be able to pull at least the XEN_DOMCTL_{,un}bind_pt_irq
    handling out of the domctl-locked region, a separate (per-domain) lock is
    needed to synchronize in particular with XEN_DOMCTL_irq_permission.
    
    Locking is added only as far as domctl-s are affected. Uses presently
    outside of the domctl lock may want dealing with subsequently (perhaps
    limited to non-__init code).
    
    This is part of XSA-492.
    
    Signed-off-by: Jan Beulich <jbeulich@xxxxxxxx>
    Reviewed-by: Roger Pau Monné <roger.pau@xxxxxxxxxx>
    Reviewed-by: Julien Grall <julien@xxxxxxx>
    (cherry picked from commit 329edc090dd5c833213bad3f13f1cbc252bc15a2)
---
 xen/arch/arm/domctl.c | 37 +++++++++++++++++++++----------------
 xen/arch/x86/domctl.c | 42 ++++++++++++++++++++++++++----------------
 xen/common/domctl.c   |  5 +++++
 3 files changed, 52 insertions(+), 32 deletions(-)

diff --git a/xen/arch/arm/domctl.c b/xen/arch/arm/domctl.c
index 1baf25c3d9..5508661fcf 100644
--- a/xen/arch/arm/domctl.c
+++ b/xen/arch/arm/domctl.c
@@ -74,6 +74,7 @@ long arch_do_domctl(struct xen_domctl *domctl, struct domain 
*d,
     case XEN_DOMCTL_bind_pt_irq:
     {
         int rc;
+        struct domain *currd = current->domain;
         struct xen_domctl_bind_pt_irq *bind = &domctl->u.bind_pt_irq;
         uint32_t irq = bind->u.spi.spi;
         uint32_t virq = bind->machine_irq;
@@ -105,21 +106,26 @@ long arch_do_domctl(struct xen_domctl *domctl, struct 
domain *d,
         if ( rc )
             return rc;
 
-        if ( !irq_access_permitted(current->domain, irq) )
-            return -EPERM;
+        read_lock(&currd->caps_lock);
 
-        if ( !vgic_reserve_virq(d, virq) )
-            return -EBUSY;
-
-        rc = route_irq_to_guest(d, virq, irq, "routed IRQ");
-        if ( rc )
-            vgic_free_virq(d, virq);
+        if ( !irq_access_permitted(currd, irq) )
+            rc = -EPERM;
+        else if ( !vgic_reserve_virq(d, virq) )
+            rc = -EBUSY;
+        else
+        {
+            rc = route_irq_to_guest(d, virq, irq, "routed IRQ");
+            if ( rc )
+                vgic_free_virq(d, virq);
+        }
 
+        read_unlock(&currd->caps_lock);
         return rc;
     }
     case XEN_DOMCTL_unbind_pt_irq:
     {
         int rc;
+        struct domain *currd = current->domain;
         struct xen_domctl_bind_pt_irq *bind = &domctl->u.bind_pt_irq;
         uint32_t irq = bind->u.spi.spi;
         uint32_t virq = bind->machine_irq;
@@ -136,16 +142,15 @@ long arch_do_domctl(struct xen_domctl *domctl, struct 
domain *d,
         if ( rc )
             return rc;
 
-        if ( !irq_access_permitted(current->domain, irq) )
-            return -EPERM;
+        read_lock(&currd->caps_lock);
 
-        rc = release_guest_irq(d, virq);
-        if ( rc )
-            return rc;
-
-        vgic_free_virq(d, virq);
+        if ( !irq_access_permitted(currd, irq) )
+            rc = -EPERM;
+        else if ( !(rc = release_guest_irq(d, virq)) )
+            vgic_free_virq(d, virq);
 
-        return 0;
+        read_unlock(&currd->caps_lock);
+        return rc;
     }
 
     case XEN_DOMCTL_vuart_op:
diff --git a/xen/arch/x86/domctl.c b/xen/arch/x86/domctl.c
index 35c44391aa..cb568bb1fe 100644
--- a/xen/arch/x86/domctl.c
+++ b/xen/arch/x86/domctl.c
@@ -536,20 +536,27 @@ long arch_do_domctl(
             break;
 
         irq = domain_pirq_to_irq(d, bind->machine_irq);
-        ret = -EPERM;
-        if ( irq <= 0 || !irq_access_permitted(currd, irq) )
-            break;
+        if ( irq <= 0 )
+            ret = -EPERM;
 
-        ret = -ESRCH;
-        if ( is_iommu_enabled(d) )
+        read_lock(&currd->caps_lock);
+
+        if ( !irq_access_permitted(currd, irq) )
+            ret = -EPERM;
+        else if ( is_iommu_enabled(d) )
         {
             pcidevs_lock();
             ret = pt_irq_create_bind(d, bind);
             pcidevs_unlock();
+
+            if ( ret < 0 )
+                printk(XENLOG_G_ERR "pt_irq_create_bind failed (%ld) for 
%pd\n",
+                       ret, d);
         }
-        if ( ret < 0 )
-            printk(XENLOG_G_ERR "pt_irq_create_bind failed (%ld) for dom%d\n",
-                   ret, d->domain_id);
+        else
+            ret = -ESRCH;
+
+        read_unlock(&currd->caps_lock);
         break;
     }
 
@@ -562,23 +569,26 @@ long arch_do_domctl(
         if ( !is_hvm_domain(d) )
             break;
 
-        ret = -EPERM;
-        if ( irq <= 0 || !irq_access_permitted(currd, irq) )
-            break;
-
         ret = xsm_unbind_pt_irq(XSM_HOOK, d, bind);
         if ( ret )
             break;
 
-        if ( is_iommu_enabled(d) )
+        read_lock(&currd->caps_lock);
+
+        if ( !irq_access_permitted(currd, irq) )
+            ret = -EPERM;
+        else if ( is_iommu_enabled(d) )
         {
             pcidevs_lock();
             ret = pt_irq_destroy_bind(d, bind);
             pcidevs_unlock();
+
+            if ( ret < 0 )
+                printk(XENLOG_G_ERR "pt_irq_destroy_bind failed (%ld) for 
%pd\n",
+                       ret, d);
         }
-        if ( ret < 0 )
-            printk(XENLOG_G_ERR "pt_irq_destroy_bind failed (%ld) for dom%d\n",
-                   ret, d->domain_id);
+
+        read_unlock(&currd->caps_lock);
         break;
     }
 
diff --git a/xen/common/domctl.c b/xen/common/domctl.c
index 96a6e4f9d8..e1237f03bb 100644
--- a/xen/common/domctl.c
+++ b/xen/common/domctl.c
@@ -728,6 +728,9 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xen_domctl_t) 
u_domctl)
             ret = -EINVAL;
             break;
         }
+
+        iocaps_double_lock(d, true);
+
         irq = pirq_access_permitted(current->domain, pirq);
         if ( !irq || xsm_irq_permission(XSM_HOOK, d, irq, allow) )
             ret = -EPERM;
@@ -735,6 +738,8 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xen_domctl_t) 
u_domctl)
             ret = irq_permit_access(d, irq);
         else
             ret = irq_deny_access(d, irq);
+
+        iocaps_double_unlock(d, true);
         break;
     }
 
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.17



 


Rackspace

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