mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 10:40:03 +01:00
[ACM] Simpler interface to hypercalls
Implement a simpler interface for the hypercalls to ACM. I put the parameters to all hypercalls into a union. On top of this I have implemented a shim layer for enabling ACM hypercalls on PPC. Signed-off-by: Stefan Berger <stefanb@us.ibm.com>
This commit is contained in:
1 parent
903fb0f33d
commit
fab51b46ae
6 files changed
+127
-106
No files matched your search
+86
-10
@@ -16,20 +16,96 @@
|
||||
|
||||
int xc_acm_op(int xc_handle, int cmd, void *arg, unsigned long arg_size)
|
||||
{
|
||||
int ret = -1;
|
||||
int ret;
|
||||
DECLARE_HYPERCALL;
|
||||
struct xen_acmctl acmctl;
|
||||
|
||||
switch (cmd) {
|
||||
case ACMOP_setpolicy: {
|
||||
struct acm_setpolicy *setpolicy = (struct acm_setpolicy *)arg;
|
||||
memcpy(&acmctl.u.setpolicy,
|
||||
setpolicy,
|
||||
sizeof(struct acm_setpolicy));
|
||||
}
|
||||
break;
|
||||
|
||||
case ACMOP_getpolicy: {
|
||||
struct acm_getpolicy *getpolicy = (struct acm_getpolicy *)arg;
|
||||
memcpy(&acmctl.u.getpolicy,
|
||||
getpolicy,
|
||||
sizeof(struct acm_getpolicy));
|
||||
}
|
||||
break;
|
||||
|
||||
case ACMOP_dumpstats: {
|
||||
struct acm_dumpstats *dumpstats = (struct acm_dumpstats *)arg;
|
||||
memcpy(&acmctl.u.dumpstats,
|
||||
dumpstats,
|
||||
sizeof(struct acm_dumpstats));
|
||||
}
|
||||
break;
|
||||
|
||||
case ACMOP_getssid: {
|
||||
struct acm_getssid *getssid = (struct acm_getssid *)arg;
|
||||
memcpy(&acmctl.u.getssid,
|
||||
getssid,
|
||||
sizeof(struct acm_getssid));
|
||||
}
|
||||
break;
|
||||
|
||||
case ACMOP_getdecision: {
|
||||
struct acm_getdecision *getdecision = (struct acm_getdecision *)arg;
|
||||
memcpy(&acmctl.u.getdecision,
|
||||
getdecision,
|
||||
sizeof(struct acm_getdecision));
|
||||
}
|
||||
break;
|
||||
|
||||
case ACMOP_chgpolicy: {
|
||||
struct acm_change_policy *change_policy = (struct acm_change_policy *)arg;
|
||||
memcpy(&acmctl.u.change_policy,
|
||||
change_policy,
|
||||
sizeof(struct acm_change_policy));
|
||||
}
|
||||
break;
|
||||
|
||||
case ACMOP_relabeldoms: {
|
||||
struct acm_relabel_doms *relabel_doms = (struct acm_relabel_doms *)arg;
|
||||
memcpy(&acmctl.u.relabel_doms,
|
||||
relabel_doms,
|
||||
sizeof(struct acm_relabel_doms));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
acmctl.cmd = cmd;
|
||||
acmctl.interface_version = ACM_INTERFACE_VERSION;
|
||||
|
||||
hypercall.op = __HYPERVISOR_acm_op;
|
||||
hypercall.arg[0] = cmd;
|
||||
hypercall.arg[1] = (unsigned long) arg;
|
||||
|
||||
if (lock_pages(arg, arg_size) != 0) {
|
||||
PERROR("xc_acm_op: arg lock failed");
|
||||
goto out;
|
||||
hypercall.arg[0] = (unsigned long)&acmctl;
|
||||
if ( lock_pages(&acmctl, sizeof(acmctl)) != 0)
|
||||
{
|
||||
PERROR("Could not lock memory for Xen hypercall");
|
||||
return -EFAULT;
|
||||
}
|
||||
ret = do_xen_hypercall(xc_handle, &hypercall);
|
||||
unlock_pages(arg, arg_size);
|
||||
out:
|
||||
if ( (ret = do_xen_hypercall(xc_handle, &hypercall)) < 0)
|
||||
{
|
||||
if ( errno == EACCES )
|
||||
DPRINTF("acmctl operation failed -- need to"
|
||||
" rebuild the user-space tool set?\n");
|
||||
}
|
||||
unlock_pages(&acmctl, sizeof(acmctl));
|
||||
|
||||
switch (cmd) {
|
||||
case ACMOP_getdecision: {
|
||||
struct acm_getdecision *getdecision = (struct acm_getdecision *)arg;
|
||||
memcpy(getdecision,
|
||||
&acmctl.u.getdecision,
|
||||
sizeof(struct acm_getdecision));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -53,7 +53,6 @@ void * __getssid(int domid, uint32_t *buflen)
|
||||
goto out2;
|
||||
}
|
||||
memset(buf, 0, SSID_BUFFER_SIZE);
|
||||
getssid.interface_version = ACM_INTERFACE_VERSION;
|
||||
set_xen_guest_handle(getssid.ssidbuf, buf);
|
||||
getssid.ssidbuf_size = SSID_BUFFER_SIZE;
|
||||
getssid.get_ssid_by = ACM_GETBY_domainid;
|
||||
@@ -163,7 +162,6 @@ static PyObject *getdecision(PyObject * self, PyObject * args)
|
||||
(strcmp(arg2_name, "domid") && strcmp(arg2_name, "ssidref")))
|
||||
return NULL;
|
||||
|
||||
getdecision.interface_version = ACM_INTERFACE_VERSION;
|
||||
getdecision.hook = ACMHOOK_sharing;
|
||||
if (!strcmp(arg1_name, "domid")) {
|
||||
getdecision.get_decision_by1 = ACM_GETBY_domainid;
|
||||
|
||||
@@ -243,7 +243,6 @@ int acm_get_ssidref(int xc_handle, int domid, uint16_t *chwall_ref,
|
||||
struct acm_getssid getssid;
|
||||
char buf[4096];
|
||||
struct acm_ssid_buffer *ssid = (struct acm_ssid_buffer *)buf;
|
||||
getssid.interface_version = ACM_INTERFACE_VERSION;
|
||||
set_xen_guest_handle(getssid.ssidbuf, buf);
|
||||
getssid.ssidbuf_size = sizeof(buf);
|
||||
getssid.get_ssid_by = ACM_GETBY_domainid;
|
||||
@@ -268,7 +267,6 @@ int acm_domain_getpolicy(int xc_handle)
|
||||
uint16_t chwall_ref, ste_ref;
|
||||
|
||||
memset(pull_buffer, 0x00, sizeof(pull_buffer));
|
||||
getpolicy.interface_version = ACM_INTERFACE_VERSION;
|
||||
set_xen_guest_handle(getpolicy.pullcache, pull_buffer);
|
||||
getpolicy.pullcache_size = sizeof(pull_buffer);
|
||||
ret = xc_acm_op(xc_handle, ACMOP_getpolicy, &getpolicy, sizeof(getpolicy));
|
||||
@@ -323,7 +321,6 @@ int acm_domain_loadpolicy(int xc_handle, const char *filename)
|
||||
struct acm_setpolicy setpolicy;
|
||||
/* dump it and then push it down into xen/acm */
|
||||
acm_dump_policy_buffer(buffer, len, chwall_ssidref, ste_ssidref);
|
||||
setpolicy.interface_version = ACM_INTERFACE_VERSION;
|
||||
set_xen_guest_handle(setpolicy.pushcache, buffer);
|
||||
setpolicy.pushcache_size = len;
|
||||
ret = xc_acm_op(xc_handle, ACMOP_setpolicy, &setpolicy, sizeof(setpolicy));
|
||||
@@ -372,7 +369,6 @@ int acm_domain_dumpstats(int xc_handle)
|
||||
struct acm_stats_buffer *stats;
|
||||
|
||||
memset(stats_buffer, 0x00, sizeof(stats_buffer));
|
||||
dumpstats.interface_version = ACM_INTERFACE_VERSION;
|
||||
set_xen_guest_handle(dumpstats.pullcache, stats_buffer);
|
||||
dumpstats.pullcache_size = sizeof(stats_buffer);
|
||||
ret = xc_acm_op(xc_handle, ACMOP_dumpstats, &dumpstats, sizeof(dumpstats));
|
||||
|
||||
+39
-81
@@ -38,69 +38,54 @@ long do_acm_op(int cmd, XEN_GUEST_HANDLE(void) arg)
|
||||
|
||||
int acm_authorize_acm_ops(struct domain *d)
|
||||
{
|
||||
/* currently, policy management functions are restricted to privileged domains */
|
||||
return (IS_PRIV(d) ? 0 : -EPERM);
|
||||
}
|
||||
|
||||
long do_acm_op(int cmd, XEN_GUEST_HANDLE(void) arg)
|
||||
|
||||
long do_acm_op(XEN_GUEST_HANDLE(xen_acmctl_t) u_acmctl)
|
||||
{
|
||||
long rc = -EFAULT;
|
||||
struct xen_acmctl curop, *op = &curop;
|
||||
|
||||
if ( acm_authorize_acm_ops(current->domain) )
|
||||
if (acm_authorize_acm_ops(current->domain))
|
||||
return -EPERM;
|
||||
|
||||
switch ( cmd )
|
||||
if ( copy_from_guest(op, u_acmctl, 1) )
|
||||
return -EFAULT;
|
||||
|
||||
if (op->interface_version != ACM_INTERFACE_VERSION)
|
||||
return -EACCES;
|
||||
|
||||
switch ( op->cmd )
|
||||
{
|
||||
|
||||
case ACMOP_setpolicy: {
|
||||
struct acm_setpolicy setpolicy;
|
||||
if (copy_from_guest(&setpolicy, arg, 1) != 0)
|
||||
return -EFAULT;
|
||||
if (setpolicy.interface_version != ACM_INTERFACE_VERSION)
|
||||
return -EACCES;
|
||||
|
||||
rc = acm_set_policy(setpolicy.pushcache,
|
||||
setpolicy.pushcache_size);
|
||||
rc = acm_set_policy(op->u.setpolicy.pushcache,
|
||||
op->u.setpolicy.pushcache_size);
|
||||
break;
|
||||
}
|
||||
|
||||
case ACMOP_getpolicy: {
|
||||
struct acm_getpolicy getpolicy;
|
||||
if (copy_from_guest(&getpolicy, arg, 1) != 0)
|
||||
return -EFAULT;
|
||||
if (getpolicy.interface_version != ACM_INTERFACE_VERSION)
|
||||
return -EACCES;
|
||||
|
||||
rc = acm_get_policy(getpolicy.pullcache,
|
||||
getpolicy.pullcache_size);
|
||||
rc = acm_get_policy(op->u.getpolicy.pullcache,
|
||||
op->u.getpolicy.pullcache_size);
|
||||
break;
|
||||
}
|
||||
|
||||
case ACMOP_dumpstats: {
|
||||
struct acm_dumpstats dumpstats;
|
||||
if (copy_from_guest(&dumpstats, arg, 1) != 0)
|
||||
return -EFAULT;
|
||||
if (dumpstats.interface_version != ACM_INTERFACE_VERSION)
|
||||
return -EACCES;
|
||||
|
||||
rc = acm_dump_statistics(dumpstats.pullcache,
|
||||
dumpstats.pullcache_size);
|
||||
rc = acm_dump_statistics(op->u.dumpstats.pullcache,
|
||||
op->u.dumpstats.pullcache_size);
|
||||
break;
|
||||
}
|
||||
|
||||
case ACMOP_getssid: {
|
||||
struct acm_getssid getssid;
|
||||
ssidref_t ssidref;
|
||||
|
||||
if (copy_from_guest(&getssid, arg, 1) != 0)
|
||||
return -EFAULT;
|
||||
if (getssid.interface_version != ACM_INTERFACE_VERSION)
|
||||
return -EACCES;
|
||||
|
||||
if (getssid.get_ssid_by == ACM_GETBY_ssidref)
|
||||
ssidref = getssid.id.ssidref;
|
||||
else if (getssid.get_ssid_by == ACM_GETBY_domainid)
|
||||
if (op->u.getssid.get_ssid_by == ACM_GETBY_ssidref)
|
||||
ssidref = op->u.getssid.id.ssidref;
|
||||
else if (op->u.getssid.get_ssid_by == ACM_GETBY_domainid)
|
||||
{
|
||||
struct domain *subj = rcu_lock_domain_by_id(getssid.id.domainid);
|
||||
struct domain *subj = rcu_lock_domain_by_id(op->u.getssid.id.domainid);
|
||||
if (!subj)
|
||||
{
|
||||
rc = -ESRCH; /* domain not found */
|
||||
@@ -120,24 +105,19 @@ long do_acm_op(int cmd, XEN_GUEST_HANDLE(void) arg)
|
||||
rc = -ESRCH;
|
||||
break;
|
||||
}
|
||||
rc = acm_get_ssid(ssidref, getssid.ssidbuf, getssid.ssidbuf_size);
|
||||
rc = acm_get_ssid(ssidref, op->u.getssid.ssidbuf,
|
||||
op->u.getssid.ssidbuf_size);
|
||||
break;
|
||||
}
|
||||
|
||||
case ACMOP_getdecision: {
|
||||
struct acm_getdecision getdecision;
|
||||
ssidref_t ssidref1, ssidref2;
|
||||
|
||||
if (copy_from_guest(&getdecision, arg, 1) != 0)
|
||||
return -EFAULT;
|
||||
if (getdecision.interface_version != ACM_INTERFACE_VERSION)
|
||||
return -EACCES;
|
||||
|
||||
if (getdecision.get_decision_by1 == ACM_GETBY_ssidref)
|
||||
ssidref1 = getdecision.id1.ssidref;
|
||||
else if (getdecision.get_decision_by1 == ACM_GETBY_domainid)
|
||||
if (op->u.getdecision.get_decision_by1 == ACM_GETBY_ssidref)
|
||||
ssidref1 = op->u.getdecision.id1.ssidref;
|
||||
else if (op->u.getdecision.get_decision_by1 == ACM_GETBY_domainid)
|
||||
{
|
||||
struct domain *subj = rcu_lock_domain_by_id(getdecision.id1.domainid);
|
||||
struct domain *subj = rcu_lock_domain_by_id(op->u.getdecision.id1.domainid);
|
||||
if (!subj)
|
||||
{
|
||||
rc = -ESRCH; /* domain not found */
|
||||
@@ -157,11 +137,11 @@ long do_acm_op(int cmd, XEN_GUEST_HANDLE(void) arg)
|
||||
rc = -ESRCH;
|
||||
break;
|
||||
}
|
||||
if (getdecision.get_decision_by2 == ACM_GETBY_ssidref)
|
||||
ssidref2 = getdecision.id2.ssidref;
|
||||
else if (getdecision.get_decision_by2 == ACM_GETBY_domainid)
|
||||
if (op->u.getdecision.get_decision_by2 == ACM_GETBY_ssidref)
|
||||
ssidref2 = op->u.getdecision.id2.ssidref;
|
||||
else if (op->u.getdecision.get_decision_by2 == ACM_GETBY_domainid)
|
||||
{
|
||||
struct domain *subj = rcu_lock_domain_by_id(getdecision.id2.domainid);
|
||||
struct domain *subj = rcu_lock_domain_by_id(op->u.getdecision.id2.domainid);
|
||||
if (!subj)
|
||||
{
|
||||
rc = -ESRCH; /* domain not found */
|
||||
@@ -181,55 +161,33 @@ long do_acm_op(int cmd, XEN_GUEST_HANDLE(void) arg)
|
||||
rc = -ESRCH;
|
||||
break;
|
||||
}
|
||||
rc = acm_get_decision(ssidref1, ssidref2, getdecision.hook);
|
||||
rc = acm_get_decision(ssidref1, ssidref2, op->u.getdecision.hook);
|
||||
|
||||
if (rc == ACM_ACCESS_PERMITTED)
|
||||
{
|
||||
getdecision.acm_decision = ACM_ACCESS_PERMITTED;
|
||||
op->u.getdecision.acm_decision = ACM_ACCESS_PERMITTED;
|
||||
rc = 0;
|
||||
}
|
||||
else if (rc == ACM_ACCESS_DENIED)
|
||||
{
|
||||
getdecision.acm_decision = ACM_ACCESS_DENIED;
|
||||
op->u.getdecision.acm_decision = ACM_ACCESS_DENIED;
|
||||
rc = 0;
|
||||
}
|
||||
else
|
||||
rc = -ESRCH;
|
||||
|
||||
if ( (rc == 0) && (copy_to_guest(arg, &getdecision, 1) != 0) )
|
||||
if ( (rc == 0) && (copy_to_guest(u_acmctl, op, 1) != 0) )
|
||||
rc = -EFAULT;
|
||||
break;
|
||||
}
|
||||
|
||||
case ACMOP_chgpolicy: {
|
||||
struct acm_change_policy chgpolicy;
|
||||
|
||||
if (copy_from_guest(&chgpolicy, arg, 1) != 0)
|
||||
return -EFAULT;
|
||||
if (chgpolicy.interface_version != ACM_INTERFACE_VERSION)
|
||||
return -EACCES;
|
||||
|
||||
rc = acm_change_policy(&chgpolicy);
|
||||
|
||||
if (rc == 0)
|
||||
if (copy_to_guest(arg, &chgpolicy, 1) != 0)
|
||||
rc = -EFAULT;
|
||||
rc = acm_change_policy(&op->u.change_policy);
|
||||
break;
|
||||
}
|
||||
|
||||
case ACMOP_relabeldoms: {
|
||||
struct acm_relabel_doms relabeldoms;
|
||||
|
||||
if (copy_from_guest(&relabeldoms, arg, 1) != 0)
|
||||
return -EFAULT;
|
||||
if (relabeldoms.interface_version != ACM_INTERFACE_VERSION)
|
||||
return -EACCES;
|
||||
|
||||
rc = acm_relabel_domains(&relabeldoms);
|
||||
|
||||
if (rc == 0)
|
||||
if (copy_to_guest(arg, &relabeldoms, 1) != 0)
|
||||
rc = -EFAULT;
|
||||
rc = acm_relabel_domains(&op->u.relabel_doms);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -241,7 +199,7 @@ long do_acm_op(int cmd, XEN_GUEST_HANDLE(void) arg)
|
||||
return rc;
|
||||
}
|
||||
|
||||
#endif /* defined(ACM_SECURITY) */
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
* This makes sure that old versions of acm tools will stop working in a
|
||||
* well-defined way (rather than crashing the machine, for instance).
|
||||
*/
|
||||
#define ACM_INTERFACE_VERSION 0xAAAA0009
|
||||
#define ACM_INTERFACE_VERSION 0xAAAA000A
|
||||
|
||||
/************************************************************************/
|
||||
|
||||
@@ -49,7 +49,6 @@
|
||||
#define ACMOP_setpolicy 1
|
||||
struct acm_setpolicy {
|
||||
/* IN */
|
||||
uint32_t interface_version;
|
||||
XEN_GUEST_HANDLE_64(void) pushcache;
|
||||
uint32_t pushcache_size;
|
||||
};
|
||||
@@ -58,7 +57,6 @@ struct acm_setpolicy {
|
||||
#define ACMOP_getpolicy 2
|
||||
struct acm_getpolicy {
|
||||
/* IN */
|
||||
uint32_t interface_version;
|
||||
XEN_GUEST_HANDLE_64(void) pullcache;
|
||||
uint32_t pullcache_size;
|
||||
};
|
||||
@@ -67,7 +65,6 @@ struct acm_getpolicy {
|
||||
#define ACMOP_dumpstats 3
|
||||
struct acm_dumpstats {
|
||||
/* IN */
|
||||
uint32_t interface_version;
|
||||
XEN_GUEST_HANDLE_64(void) pullcache;
|
||||
uint32_t pullcache_size;
|
||||
};
|
||||
@@ -78,7 +75,6 @@ struct acm_dumpstats {
|
||||
#define ACM_GETBY_domainid 2
|
||||
struct acm_getssid {
|
||||
/* IN */
|
||||
uint32_t interface_version;
|
||||
uint32_t get_ssid_by; /* ACM_GETBY_* */
|
||||
union {
|
||||
domaintype_t domainid;
|
||||
@@ -91,7 +87,6 @@ struct acm_getssid {
|
||||
#define ACMOP_getdecision 5
|
||||
struct acm_getdecision {
|
||||
/* IN */
|
||||
uint32_t interface_version;
|
||||
uint32_t get_decision_by1; /* ACM_GETBY_* */
|
||||
uint32_t get_decision_by2; /* ACM_GETBY_* */
|
||||
union {
|
||||
@@ -111,7 +106,6 @@ struct acm_getdecision {
|
||||
#define ACMOP_chgpolicy 6
|
||||
struct acm_change_policy {
|
||||
/* IN */
|
||||
uint32_t interface_version;
|
||||
XEN_GUEST_HANDLE_64(void) policy_pushcache;
|
||||
uint32_t policy_pushcache_size;
|
||||
XEN_GUEST_HANDLE_64(void) del_array;
|
||||
@@ -127,7 +121,6 @@ struct acm_change_policy {
|
||||
#define ACMOP_relabeldoms 7
|
||||
struct acm_relabel_doms {
|
||||
/* IN */
|
||||
uint32_t interface_version;
|
||||
XEN_GUEST_HANDLE_64(void) relabel_map;
|
||||
uint32_t relabel_map_size;
|
||||
/* OUT */
|
||||
|
||||
@@ -98,7 +98,7 @@ do_vcpu_op(
|
||||
|
||||
extern long
|
||||
do_acm_op(
|
||||
int cmd, XEN_GUEST_HANDLE(void) arg);
|
||||
XEN_GUEST_HANDLE(xen_acmctl_t) arg);
|
||||
|
||||
extern long
|
||||
do_nmi_op(
|
||||
|
||||