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

[xen stable-4.21] domain: locking for iomem_caps accesses



commit 06ca3bef324ad44daa5691ab1d98f874325aed22
Author:     Jan Beulich <jbeulich@xxxxxxxx>
AuthorDate: Thu Jun 4 21:37:32 2026 +0100
Commit:     Andrew Cooper <andrew.cooper3@xxxxxxxxxx>
CommitDate: Thu Jun 4 21:38:04 2026 +0100

    domain: locking for iomem_caps accesses
    
    In order to be able to pull at least the XEN_DOMCTL_iomem_mapping handling
    out of the domctl-locked region, a separate (per-domain) lock is needed to
    synchronize in particular with XEN_DOMCTL_iomem_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>
    (cherry picked from commit 960713dfd4a405e67e9f174302f8f9fd9e0e50dc)
---
 xen/common/domain.c     |  6 ++++++
 xen/common/domctl.c     | 53 +++++++++++++++++++++++++++++++++++++++----------
 xen/include/xen/iocap.h |  3 +++
 xen/include/xen/sched.h |  1 +
 4 files changed, 52 insertions(+), 11 deletions(-)

diff --git a/xen/common/domain.c b/xen/common/domain.c
index dfeb6c7558..69fe1debcc 100644
--- a/xen/common/domain.c
+++ b/xen/common/domain.c
@@ -518,10 +518,15 @@ static int late_hwdom_init(struct domain *d)
      * may be modified after this hypercall returns if a more complex
      * device model is desired.
      */
+    write_lock(&dom0->caps_lock);
     rangeset_swap(d->irq_caps, dom0->irq_caps);
     rangeset_swap(d->iomem_caps, dom0->iomem_caps);
 #ifdef CONFIG_X86
     rangeset_swap(d->arch.ioport_caps, dom0->arch.ioport_caps);
+#endif
+    write_unlock(&dom0->caps_lock);
+
+#ifdef CONFIG_X86
     setup_io_bitmap(d);
     setup_io_bitmap(dom0);
 #endif
@@ -873,6 +878,7 @@ struct domain *domain_create(domid_t domid,
     rspin_lock_init_prof(d, domain_lock);
     rspin_lock_init_prof(d, page_alloc_lock);
     spin_lock_init(&d->hypercall_deadlock_mutex);
+    rwlock_init(&d->caps_lock);
     INIT_PAGE_LIST_HEAD(&d->page_list);
     INIT_PAGE_LIST_HEAD(&d->extra_page_list);
     INIT_PAGE_LIST_HEAD(&d->xenpage_list);
diff --git a/xen/common/domctl.c b/xen/common/domctl.c
index 509347822c..ba3667c4ca 100644
--- a/xen/common/domctl.c
+++ b/xen/common/domctl.c
@@ -267,6 +267,35 @@ static struct vnuma_info *vnuma_init(const struct 
xen_domctl_vnuma *uinfo,
     return ERR_PTR(ret);
 }
 
+void iocaps_double_lock(struct domain *d, bool write)
+{
+    struct domain *currd = current->domain;
+
+    if ( d->domain_id > currd->domain_id )
+        read_lock(&currd->caps_lock);
+
+    if ( write )
+        write_lock(&d->caps_lock);
+    else
+        read_lock(&d->caps_lock);
+
+    if ( d->domain_id < currd->domain_id )
+        read_lock(&currd->caps_lock);
+}
+
+void iocaps_double_unlock(struct domain *d, bool write)
+{
+    struct domain *currd = current->domain;
+
+    if ( d != currd )
+        read_unlock(&currd->caps_lock);
+
+    if ( write )
+        write_unlock(&d->caps_lock);
+    else
+        read_unlock(&d->caps_lock);
+}
+
 static bool is_stable_domctl(uint32_t cmd)
 {
     return cmd == XEN_DOMCTL_get_domain_state;
@@ -687,6 +716,8 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xen_domctl_t) 
u_domctl)
         if ( (mfn + nr_mfns - 1) < mfn ) /* wrap? */
             break;
 
+        iocaps_double_lock(d, true);
+
         if ( !iomem_access_permitted(current->domain,
                                      mfn, mfn + nr_mfns - 1) ||
              xsm_iomem_permission(XSM_HOOK, d, mfn, mfn + nr_mfns - 1, allow) )
@@ -695,6 +726,8 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xen_domctl_t) 
u_domctl)
             ret = iomem_permit_access(d, mfn, mfn + nr_mfns - 1);
         else
             ret = iomem_deny_access(d, mfn, mfn + nr_mfns - 1);
+
+        iocaps_double_unlock(d, true);
         break;
     }
 
@@ -719,19 +752,15 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xen_domctl_t) 
u_domctl)
             break;
 #endif
 
+        iocaps_double_lock(d, false);
+
         ret = -EPERM;
         if ( !iomem_access_permitted(current->domain, mfn, mfn_end) ||
-             !iomem_access_permitted(d, mfn, mfn_end) )
-            break;
-
-        ret = xsm_iomem_mapping(XSM_HOOK, d, mfn, mfn_end, add);
-        if ( ret )
-            break;
-
-        if ( !paging_mode_translate(d) )
-            break;
-
-        if ( add )
+             !iomem_access_permitted(d, mfn, mfn_end) ||
+             (ret = xsm_iomem_mapping(XSM_HOOK, d, mfn, mfn_end, add)) ||
+             !paging_mode_translate(d) )
+            /* Nothing. */;
+        else if ( add )
         {
             printk(XENLOG_G_DEBUG
                    "memory_map:add: dom%d gfn=%lx mfn=%lx nr=%lx\n",
@@ -755,6 +784,8 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xen_domctl_t) 
u_domctl)
                        "memory_map: error %ld removing dom%d access to 
[%lx,%lx]\n",
                        ret, d->domain_id, mfn, mfn_end);
         }
+
+        iocaps_double_unlock(d, false);
         break;
     }
 
diff --git a/xen/include/xen/iocap.h b/xen/include/xen/iocap.h
index ffbc48b60f..cb36ebbeeb 100644
--- a/xen/include/xen/iocap.h
+++ b/xen/include/xen/iocap.h
@@ -12,6 +12,9 @@
 #include <asm/iocap.h>
 #include <asm/p2m.h>
 
+void iocaps_double_lock(struct domain *d, bool write);
+void iocaps_double_unlock(struct domain *d, bool write);
+
 static inline int iomem_permit_access(struct domain *d, unsigned long s,
                                       unsigned long e)
 {
diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h
index d867fa5745..f42fcaf20e 100644
--- a/xen/include/xen/sched.h
+++ b/xen/include/xen/sched.h
@@ -536,6 +536,7 @@ struct domain
 #endif
 
     /* I/O capabilities (access to IRQs and memory-mapped I/O). */
+    rwlock_t         caps_lock;
     struct rangeset *iomem_caps;
     struct rangeset *irq_caps;
 
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.21



 


Rackspace

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