diff options
-rw-r--r-- | xen/Rules.mk | 7 | ||||
-rw-r--r-- | xen/arch/x86/irq.c | 2 | ||||
-rw-r--r-- | xen/arch/x86/physdev.c | 17 | ||||
-rw-r--r-- | xen/common/domctl.c | 28 | ||||
-rw-r--r-- | xen/include/xen/config.h | 6 |
5 files changed, 48 insertions, 12 deletions
diff --git a/xen/Rules.mk b/xen/Rules.mk index 5601e45191..3f141c33bc 100644 --- a/xen/Rules.mk +++ b/xen/Rules.mk @@ -9,6 +9,9 @@ perfc_arrays ?= n crash_debug ?= n frame_pointer ?= n +# Allow some delicate passthrough related hypercalls to be made from a stubdom +privileged_stubdoms ?= y + XEN_ROOT=$(BASEDIR)/.. include $(XEN_ROOT)/Config.mk @@ -58,6 +61,10 @@ ifneq ($(max_phys_irqs),) CFLAGS-y += -DMAX_PHYS_IRQS=$(max_phys_irqs) endif +ifeq ($(privileged_stubdoms),y) +CFLAGS += -DPRIVILEGED_STUBDOMS +endif + AFLAGS-y += -D__ASSEMBLY__ ALL_OBJS := $(ALL_OBJS-y) diff --git a/xen/arch/x86/irq.c b/xen/arch/x86/irq.c index 2ca28ac281..d4bf176d07 100644 --- a/xen/arch/x86/irq.c +++ b/xen/arch/x86/irq.c @@ -1340,7 +1340,7 @@ int map_domain_pirq( ASSERT(spin_is_locked(&pcidevs_lock)); ASSERT(spin_is_locked(&d->event_lock)); - if ( !IS_PRIV(current->domain) ) + if ( !STUBDOM_IS_PRIV_FOR(current->domain, d) ) return -EPERM; if ( pirq < 0 || pirq >= d->nr_pirqs || irq < 0 || irq >= nr_irqs ) diff --git a/xen/arch/x86/physdev.c b/xen/arch/x86/physdev.c index 474dcf21c3..0c284e84bc 100644 --- a/xen/arch/x86/physdev.c +++ b/xen/arch/x86/physdev.c @@ -34,9 +34,6 @@ static int physdev_map_pirq(struct physdev_map_pirq *map) struct msi_info _msi; void *map_data = NULL; - if ( !IS_PRIV(current->domain) ) - return -EPERM; - if ( !map ) return -EINVAL; @@ -46,8 +43,11 @@ static int physdev_map_pirq(struct physdev_map_pirq *map) d = rcu_lock_domain_by_id(map->domid); if ( d == NULL ) + return -ESRCH; + + if ( !STUBDOM_IS_PRIV_FOR(current->domain, d) ) { - ret = -ESRCH; + ret = -EPERM; goto free_domain; } @@ -160,9 +160,6 @@ static int physdev_unmap_pirq(struct physdev_unmap_pirq *unmap) struct domain *d; int ret; - if ( !IS_PRIV(current->domain) ) - return -EPERM; - if ( unmap->domid == DOMID_SELF ) d = rcu_lock_domain(current->domain); else @@ -171,14 +168,18 @@ static int physdev_unmap_pirq(struct physdev_unmap_pirq *unmap) if ( d == NULL ) return -ESRCH; + ret = -EPERM; + if ( !STUBDOM_IS_PRIV_FOR(current->domain, d) ) + goto free_domain; + spin_lock(&pcidevs_lock); spin_lock(&d->event_lock); ret = unmap_domain_pirq(d, unmap->pirq); spin_unlock(&d->event_lock); spin_unlock(&pcidevs_lock); +free_domain: rcu_unlock_domain(d); - return ret; } diff --git a/xen/common/domctl.c b/xen/common/domctl.c index e21d565937..60f8e00087 100644 --- a/xen/common/domctl.c +++ b/xen/common/domctl.c @@ -220,15 +220,37 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domctl_t) u_domctl) long ret = 0; struct xen_domctl curop, *op = &curop; - if ( !IS_PRIV(current->domain) ) - return -EPERM; - if ( copy_from_guest(op, u_domctl, 1) ) return -EFAULT; if ( op->interface_version != XEN_DOMCTL_INTERFACE_VERSION ) return -EACCES; + switch ( op->cmd ) + { + case XEN_DOMCTL_ioport_mapping: + case XEN_DOMCTL_memory_mapping: + case XEN_DOMCTL_bind_pt_irq: + case XEN_DOMCTL_unbind_pt_irq: + case XEN_DOMCTL_assign_device: + case XEN_DOMCTL_deassign_device: { + struct domain *d = get_domain_by_id(op->domain); + bool_t is_priv = IS_PRIV(current->domain); + if ( !is_priv && ((d = rcu_lock_domain_by_id(op->domain)) != NULL) ) + { + is_priv = STUBDOM_IS_PRIV_FOR(current->domain, d); + rcu_unlock_domain(d); + } + if ( !is_priv ) + return -EPERM; + break; + } + default: + if ( !IS_PRIV(current->domain) ) + return -EPERM; + break; + } + if ( !domctl_lock_acquire() ) return hypercall_create_continuation( __HYPERVISOR_domctl, "h", u_domctl); diff --git a/xen/include/xen/config.h b/xen/include/xen/config.h index 7872f13e8d..43d6bc6cff 100644 --- a/xen/include/xen/config.h +++ b/xen/include/xen/config.h @@ -95,4 +95,10 @@ int current_domain_id(void); #define __cpuinitdata #define __cpuinit +#ifdef PRIVILEGED_STUBDOMS +#define STUBDOM_IS_PRIV_FOR(x,y) IS_PRIV_FOR(x,y) +#else +#define STUBDOM_IS_PRIV_FOR(x,y) IS_PRIV(x) +#endif + #endif /* __XEN_CONFIG_H__ */ |