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@suse.com>
Reviewed-by: Roger Pau Monné <roger.pau@citrix.com>
(cherry picked from commit 960713dfd4)
This commit is contained in:
Jan Beulich authored and Andrew Cooper committed 2026-06-04 22:29:00 +01:00
1 parent 64327f3e89
commit f91eab583f
4 files changed
+52 -11

No files matched your search

+6
View File
@@ -332,10 +332,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
@@ -631,6 +636,7 @@ struct domain *domain_create(domid_t domid,
spin_lock_init_prof(d, domain_lock);
spin_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);
+42 -11
View File
@@ -278,6 +278,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);
}
long do_domctl(XEN_GUEST_HANDLE_PARAM(xen_domctl_t) u_domctl)
{
long ret = 0;
@@ -689,6 +718,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) )
@@ -697,6 +728,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;
}
@@ -721,19 +754,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",
@@ -757,6 +786,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;
}
+3
View File
@@ -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)
{
+1
View File
@@ -493,6 +493,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;
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.