From: Oleksandr Tyshchenko <oleksandr_tyshchenko@epam.com>
Trying to run emulator in driver domain I ran into various issues
mostly policy-related. So this patch tries to resolve all them
plobably in a hackish way. I would like to get feedback how
to implement them properly as having an emulator in driver domain
is a completely valid use-case.
Signed-off-by: Oleksandr Tyshchenko <oleksandr_tyshchenko@epam.com>
---
xen/common/domain.c | 15 +++++++++++++++
xen/common/domctl.c | 8 +++++++-
xen/common/event_channel.c | 14 ++++++++++++--
xen/common/memory.c | 6 ++++++
xen/include/xsm/dummy.h | 16 +++++++++++++---
5 files changed, 53 insertions(+), 6 deletions(-)
diff --git a/xen/common/domain.c b/xen/common/domain.c
index e9be05f..5c9fef2 100644
--- a/xen/common/domain.c
+++ b/xen/common/domain.c
@@ -695,6 +695,7 @@ int domain_kill(struct domain *d)
{
int rc = 0;
struct vcpu *v;
+ struct domain *td;
if ( d == current->domain )
return -EINVAL;
@@ -733,6 +734,20 @@ int domain_kill(struct domain *d)
* have to be put before we call put_domain. */
vm_event_cleanup(d);
put_domain(d);
+ /*
+ * XEN_DOMCTL_set_target implementation holds reference on
+ * target domain which doesn't allow to completely destroy it.
+ * Check if the reference are hold by someone and drop it
+ * when destroying target domain.
+ */
+ for_each_domain ( td ) {
+ if ( td->target == d ) {
+ td->target = NULL;
+ put_domain(d);
+ break;
+ }
+ }
+
send_global_virq(VIRQ_DOM_EXC);
/* fallthrough */
case DOMDYING_dead:
diff --git a/xen/common/domctl.c b/xen/common/domctl.c
index a69b3b5..079c7b0 100644
--- a/xen/common/domctl.c
+++ b/xen/common/domctl.c
@@ -871,6 +871,12 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xen_domctl_t) u_domctl)
if ( (d == e) || (d->target != NULL) )
{
put_domain(e);
+ /*
+ * Be a little bit more polite here, looks like the emulator
+ * has just been restarted.
+ */
+ if ( d->target == e )
+ ret = 0;
break;
}
@@ -883,7 +889,7 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xen_domctl_t) u_domctl)
break;
}
- /* Hold reference on @e until we destroy @d. */
+ /* Hold reference on @e until we destroy either @d or @e */
d->target = e;
break;
}
diff --git a/xen/common/event_channel.c b/xen/common/event_channel.c
index a8d182b5..2aa497a 100644
--- a/xen/common/event_channel.c
+++ b/xen/common/event_channel.c
@@ -235,7 +235,12 @@ static long evtchn_alloc_unbound(evtchn_alloc_unbound_t *alloc)
ERROR_EXIT_DOM(port, d);
chn = evtchn_from_port(d, port);
- rc = xsm_evtchn_unbound(XSM_TARGET, d, chn, alloc->remote_dom);
+ /*
+ * XXX: XSM_TARGET is not functional for emulator running in driver domain.
+ * See xsm_default_action for details. Probably XSM_DM_PRIV could work,
+ * but there is a risk to break other users.
+ */
+ rc = xsm_evtchn_unbound(XSM_HOOK, d, chn, alloc->remote_dom);
if ( rc )
goto out;
@@ -1218,7 +1223,12 @@ int alloc_unbound_xen_event_channel(
port = rc;
chn = evtchn_from_port(ld, port);
- rc = xsm_evtchn_unbound(XSM_TARGET, ld, chn, remote_domid);
+ /*
+ * XXX: XSM_TARGET is not functional for emulator running in driver domain.
+ * See xsm_default_action for details. Probably XSM_DM_PRIV could work,
+ * but there is a risk to break other users.
+ */
+ rc = xsm_evtchn_unbound(XSM_HOOK, ld, chn, remote_domid);
if ( rc )
goto out;
diff --git a/xen/common/memory.c b/xen/common/memory.c
index 0000477..8b306f6 100644
--- a/xen/common/memory.c
+++ b/xen/common/memory.c
@@ -1153,12 +1153,18 @@ static int acquire_resource(
unsigned int i;
/*
+ * XXX: Ugly hack for now to let emulator running in driver domain
+ * to succeeded in acquiring resource.
+ */
+#if 0
+ /*
* FIXME: Until foreign pages inserted into the P2M are properly
* reference counted, it is unsafe to allow mapping of
* resource pages unless the caller is the hardware domain.
*/
if ( !is_hardware_domain(currd) )
return -EACCES;
+#endif
if ( copy_from_guest(gfn_list, xmar.frame_list, xmar.nr_frames) )
rc = -EFAULT;
diff --git a/xen/include/xsm/dummy.h b/xen/include/xsm/dummy.h
index 317455a..c0813c0 100644
--- a/xen/include/xsm/dummy.h
+++ b/xen/include/xsm/dummy.h
@@ -139,13 +139,23 @@ static XSM_INLINE int xsm_domctl(XSM_DEFAULT_ARG struct domain *d, int cmd)
XSM_ASSERT_ACTION(XSM_OTHER);
switch ( cmd )
{
+ /*
+ * XXX: Emulator running in driver domain tries to get vcpus num.
+ * Probably we could avoid that change by modifying emulator to not use
+ * domctl for getting vcpus num.
+ */
+ case XEN_DOMCTL_getdomaininfo:
+ /*
+ * XXX: XSM_DM_PRIV is not functional for emulator running in driver domain
+ * without setting a target in advance. See xsm_default_action for details.
+ */
+ case XEN_DOMCTL_set_target:
+ return xsm_default_action(XSM_HOOK, current->domain, d);
case XEN_DOMCTL_ioport_mapping:
case XEN_DOMCTL_memory_mapping:
case XEN_DOMCTL_bind_pt_irq:
case XEN_DOMCTL_unbind_pt_irq:
return xsm_default_action(XSM_DM_PRIV, current->domain, d);
- case XEN_DOMCTL_getdomaininfo:
- return xsm_default_action(XSM_XS_PRIV, current->domain, d);
default:
return xsm_default_action(XSM_PRIV, current->domain, d);
}
@@ -275,7 +285,7 @@ static XSM_INLINE int xsm_claim_pages(XSM_DEFAULT_ARG struct domain *d)
static XSM_INLINE int xsm_evtchn_unbound(XSM_DEFAULT_ARG struct domain *d, struct evtchn *chn,
domid_t id2)
{
- XSM_ASSERT_ACTION(XSM_TARGET);
+ XSM_ASSERT_ACTION(XSM_HOOK);
return xsm_default_action(action, current->domain, d);
}
--
2.7.4
Trying to run emulator in driver domain I ran into various issues
mostly policy-related. So this patch tries to resolve all them
plobably in a hackish way. I would like to get feedback how
to implement them properly as having an emulator in driver domain
is a completely valid use-case.
Signed-off-by: Oleksandr Tyshchenko <oleksandr_tyshchenko@epam.com>
---
xen/common/domain.c | 15 +++++++++++++++
xen/common/domctl.c | 8 +++++++-
xen/common/event_channel.c | 14 ++++++++++++--
xen/common/memory.c | 6 ++++++
xen/include/xsm/dummy.h | 16 +++++++++++++---
5 files changed, 53 insertions(+), 6 deletions(-)
diff --git a/xen/common/domain.c b/xen/common/domain.c
index e9be05f..5c9fef2 100644
--- a/xen/common/domain.c
+++ b/xen/common/domain.c
@@ -695,6 +695,7 @@ int domain_kill(struct domain *d)
{
int rc = 0;
struct vcpu *v;
+ struct domain *td;
if ( d == current->domain )
return -EINVAL;
@@ -733,6 +734,20 @@ int domain_kill(struct domain *d)
* have to be put before we call put_domain. */
vm_event_cleanup(d);
put_domain(d);
+ /*
+ * XEN_DOMCTL_set_target implementation holds reference on
+ * target domain which doesn't allow to completely destroy it.
+ * Check if the reference are hold by someone and drop it
+ * when destroying target domain.
+ */
+ for_each_domain ( td ) {
+ if ( td->target == d ) {
+ td->target = NULL;
+ put_domain(d);
+ break;
+ }
+ }
+
send_global_virq(VIRQ_DOM_EXC);
/* fallthrough */
case DOMDYING_dead:
diff --git a/xen/common/domctl.c b/xen/common/domctl.c
index a69b3b5..079c7b0 100644
--- a/xen/common/domctl.c
+++ b/xen/common/domctl.c
@@ -871,6 +871,12 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xen_domctl_t) u_domctl)
if ( (d == e) || (d->target != NULL) )
{
put_domain(e);
+ /*
+ * Be a little bit more polite here, looks like the emulator
+ * has just been restarted.
+ */
+ if ( d->target == e )
+ ret = 0;
break;
}
@@ -883,7 +889,7 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xen_domctl_t) u_domctl)
break;
}
- /* Hold reference on @e until we destroy @d. */
+ /* Hold reference on @e until we destroy either @d or @e */
d->target = e;
break;
}
diff --git a/xen/common/event_channel.c b/xen/common/event_channel.c
index a8d182b5..2aa497a 100644
--- a/xen/common/event_channel.c
+++ b/xen/common/event_channel.c
@@ -235,7 +235,12 @@ static long evtchn_alloc_unbound(evtchn_alloc_unbound_t *alloc)
ERROR_EXIT_DOM(port, d);
chn = evtchn_from_port(d, port);
- rc = xsm_evtchn_unbound(XSM_TARGET, d, chn, alloc->remote_dom);
+ /*
+ * XXX: XSM_TARGET is not functional for emulator running in driver domain.
+ * See xsm_default_action for details. Probably XSM_DM_PRIV could work,
+ * but there is a risk to break other users.
+ */
+ rc = xsm_evtchn_unbound(XSM_HOOK, d, chn, alloc->remote_dom);
if ( rc )
goto out;
@@ -1218,7 +1223,12 @@ int alloc_unbound_xen_event_channel(
port = rc;
chn = evtchn_from_port(ld, port);
- rc = xsm_evtchn_unbound(XSM_TARGET, ld, chn, remote_domid);
+ /*
+ * XXX: XSM_TARGET is not functional for emulator running in driver domain.
+ * See xsm_default_action for details. Probably XSM_DM_PRIV could work,
+ * but there is a risk to break other users.
+ */
+ rc = xsm_evtchn_unbound(XSM_HOOK, ld, chn, remote_domid);
if ( rc )
goto out;
diff --git a/xen/common/memory.c b/xen/common/memory.c
index 0000477..8b306f6 100644
--- a/xen/common/memory.c
+++ b/xen/common/memory.c
@@ -1153,12 +1153,18 @@ static int acquire_resource(
unsigned int i;
/*
+ * XXX: Ugly hack for now to let emulator running in driver domain
+ * to succeeded in acquiring resource.
+ */
+#if 0
+ /*
* FIXME: Until foreign pages inserted into the P2M are properly
* reference counted, it is unsafe to allow mapping of
* resource pages unless the caller is the hardware domain.
*/
if ( !is_hardware_domain(currd) )
return -EACCES;
+#endif
if ( copy_from_guest(gfn_list, xmar.frame_list, xmar.nr_frames) )
rc = -EFAULT;
diff --git a/xen/include/xsm/dummy.h b/xen/include/xsm/dummy.h
index 317455a..c0813c0 100644
--- a/xen/include/xsm/dummy.h
+++ b/xen/include/xsm/dummy.h
@@ -139,13 +139,23 @@ static XSM_INLINE int xsm_domctl(XSM_DEFAULT_ARG struct domain *d, int cmd)
XSM_ASSERT_ACTION(XSM_OTHER);
switch ( cmd )
{
+ /*
+ * XXX: Emulator running in driver domain tries to get vcpus num.
+ * Probably we could avoid that change by modifying emulator to not use
+ * domctl for getting vcpus num.
+ */
+ case XEN_DOMCTL_getdomaininfo:
+ /*
+ * XXX: XSM_DM_PRIV is not functional for emulator running in driver domain
+ * without setting a target in advance. See xsm_default_action for details.
+ */
+ case XEN_DOMCTL_set_target:
+ return xsm_default_action(XSM_HOOK, current->domain, d);
case XEN_DOMCTL_ioport_mapping:
case XEN_DOMCTL_memory_mapping:
case XEN_DOMCTL_bind_pt_irq:
case XEN_DOMCTL_unbind_pt_irq:
return xsm_default_action(XSM_DM_PRIV, current->domain, d);
- case XEN_DOMCTL_getdomaininfo:
- return xsm_default_action(XSM_XS_PRIV, current->domain, d);
default:
return xsm_default_action(XSM_PRIV, current->domain, d);
}
@@ -275,7 +285,7 @@ static XSM_INLINE int xsm_claim_pages(XSM_DEFAULT_ARG struct domain *d)
static XSM_INLINE int xsm_evtchn_unbound(XSM_DEFAULT_ARG struct domain *d, struct evtchn *chn,
domid_t id2)
{
- XSM_ASSERT_ACTION(XSM_TARGET);
+ XSM_ASSERT_ACTION(XSM_HOOK);
return xsm_default_action(action, current->domain, d);
}
--
2.7.4