aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--xen/Rules.mk7
-rw-r--r--xen/arch/x86/irq.c2
-rw-r--r--xen/arch/x86/physdev.c17
-rw-r--r--xen/common/domctl.c28
-rw-r--r--xen/include/xen/config.h6
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__ */