# HG changeset patch
# User kfraser@xxxxxxxxxxxxxxxxxxxxx
# Date 1185523275 -3600
# Node ID bf512fde6667f213dc5e32239fd567e2b5a6ef37
# Parent 07655ed2fe58ebf883b8a4b5c2dccf15576f4778
[ACM] Check a domain's authorization to run.
A domain is only authorized to run if it has a superset of Simple Type
Enforcement Types in its VM label compared to that of Domain-0, which
itself may not have all STEs available in a policy. This patch adds a
check for this into Xend and the necessary code support into Xen.
Signed-off-by: Stefan Berger <stefanb@xxxxxxxxxx>
---
tools/python/xen/lowlevel/acm/acm.c | 9 ++--
tools/python/xen/util/security.py | 22 +++++++++-
tools/python/xen/xend/XendDomainInfo.py | 10 +++-
xen/acm/acm_chinesewall_hooks.c | 1
xen/acm/acm_core.c | 29 -------------
xen/acm/acm_policy.c | 4 +
xen/acm/acm_simple_type_enforcement_hooks.c | 38 ++++++++++++++++-
xen/include/acm/acm_core.h | 3 -
xen/include/acm/acm_hooks.h | 60 +++++++++++++++++++++-------
xen/include/public/acm.h | 5 +-
10 files changed, 125 insertions(+), 56 deletions(-)
diff -r 07655ed2fe58 -r bf512fde6667 tools/python/xen/lowlevel/acm/acm.c
--- a/tools/python/xen/lowlevel/acm/acm.c Thu Jul 26 12:00:32 2007 +0100
+++ b/tools/python/xen/lowlevel/acm/acm.c Fri Jul 27 09:01:15 2007 +0100
@@ -148,9 +148,10 @@ static PyObject *getdecision(PyObject *
char *arg1_name, *arg1, *arg2_name, *arg2, *decision = NULL;
struct acm_getdecision getdecision;
int xc_handle, rc;
-
- if (!PyArg_ParseTuple(args, "ssss", &arg1_name,
- &arg1, &arg2_name, &arg2)) {
+ uint32_t hooktype;
+
+ if (!PyArg_ParseTuple(args, "ssssi", &arg1_name,
+ &arg1, &arg2_name, &arg2, &hooktype)) {
return NULL;
}
@@ -163,7 +164,7 @@ static PyObject *getdecision(PyObject *
(strcmp(arg2_name, "domid") && strcmp(arg2_name, "ssidref")))
return NULL;
- getdecision.hook = ACMHOOK_sharing;
+ getdecision.hook = hooktype;
if (!strcmp(arg1_name, "domid")) {
getdecision.get_decision_by1 = ACM_GETBY_domainid;
getdecision.id1.domainid = atoi(arg1);
diff -r 07655ed2fe58 -r bf512fde6667 tools/python/xen/util/security.py
--- a/tools/python/xen/util/security.py Thu Jul 26 12:00:32 2007 +0100
+++ b/tools/python/xen/util/security.py Fri Jul 27 09:01:15 2007 +0100
@@ -61,6 +61,10 @@ empty_line_re = re.compile("^\s*$")
empty_line_re = re.compile("^\s*$")
binary_name_re = re.compile(".*[chwall|ste|chwall_ste].*\.bin", re.IGNORECASE)
policy_name_re = re.compile(".*[chwall|ste|chwall_ste].*", re.IGNORECASE)
+
+#decision hooks known to the hypervisor
+ACMHOOK_sharing = 1
+ACMHOOK_authorization = 2
#other global variables
NULL_SSIDREF = 0
@@ -453,7 +457,8 @@ def get_decision(arg1, arg2):
err("Invalid id or ssidref type, string or int required")
try:
- decision = acm.getdecision(arg1[0], arg1[1], arg2[0], arg2[1])
+ decision = acm.getdecision(arg1[0], arg1[1], arg2[0], arg2[1],
+ ACMHOOK_sharing)
except:
err("Cannot determine decision.")
@@ -461,6 +466,21 @@ def get_decision(arg1, arg2):
return decision
else:
err("Cannot determine decision (Invalid parameter).")
+
+
+def has_authorization(ssidref):
+ """ Check if the domain with the given ssidref has authorization to
+ run on this system. To have authoriztion dom0's STE types must
+ be a superset of that of the domain's given through its ssidref.
+ """
+ rc = True
+ dom0_ssidref = int(acm.getssid(0)['ssidref'])
+ decision = acm.getdecision('ssidref', str(dom0_ssidref),
+ 'ssidref', str(ssidref),
+ ACMHOOK_authorization)
+ if decision == "DENIED":
+ rc = False
+ return rc
def hv_chg_policy(bin_pol, del_array, chg_array):
diff -r 07655ed2fe58 -r bf512fde6667 tools/python/xen/xend/XendDomainInfo.py
--- a/tools/python/xen/xend/XendDomainInfo.py Thu Jul 26 12:00:32 2007 +0100
+++ b/tools/python/xen/xend/XendDomainInfo.py Fri Jul 27 09:01:15 2007 +0100
@@ -1460,9 +1460,13 @@ class XendDomainInfo:
# allocation of 1MB. We free up 2MB here to be on the safe side.
balloon.free(2*1024) # 2MB should be plenty
- ssidref = security.calc_dom_ssidref_from_info(self.info)
- if ssidref == 0 and security.on():
- raise VmError('VM is not properly labeled.')
+ ssidref = 0
+ if security.on():
+ ssidref = security.calc_dom_ssidref_from_info(self.info)
+ if ssidref == 0:
+ raise VmError('VM is not properly labeled.')
+ if security.has_authorization(ssidref) == False:
+ raise VmError("VM is not authorized to run.")
try:
self.domid = xc.domain_create(
diff -r 07655ed2fe58 -r bf512fde6667 xen/acm/acm_chinesewall_hooks.c
--- a/xen/acm/acm_chinesewall_hooks.c Thu Jul 26 12:00:32 2007 +0100
+++ b/xen/acm/acm_chinesewall_hooks.c Fri Jul 27 09:01:15 2007 +0100
@@ -685,6 +685,7 @@ struct acm_operations acm_chinesewall_op
.fail_grant_setup = NULL,
/* generic domain-requested decision hooks */
.sharing = NULL,
+ .authorization = NULL,
.is_default_policy = chwall_is_default_policy,
};
diff -r 07655ed2fe58 -r bf512fde6667 xen/acm/acm_core.c
--- a/xen/acm/acm_core.c Thu Jul 26 12:00:32 2007 +0100
+++ b/xen/acm/acm_core.c Fri Jul 27 09:01:15 2007 +0100
@@ -314,26 +314,7 @@ acm_init(char *policy_start,
return ret;
}
-int
-acm_init_domain_ssid(domid_t id, ssidref_t ssidref)
-{
- struct domain *subj = rcu_lock_domain_by_id(id);
- int ret;
-
- if (subj == NULL)
- {
- printk("%s: ACM_NULL_POINTER ERROR (id=%x).\n", __func__, id);
- return ACM_NULL_POINTER_ERROR;
- }
-
- ret = acm_init_domain_ssid_new(subj, ssidref);
-
- rcu_unlock_domain(subj);
-
- return ret;
-}
-
-int acm_init_domain_ssid_new(struct domain *subj, ssidref_t ssidref)
+int acm_init_domain_ssid(struct domain *subj, ssidref_t ssidref)
{
struct acm_ssid_domain *ssid;
int ret1, ret2;
@@ -373,10 +354,6 @@ int acm_init_domain_ssid_new(struct doma
acm_free_domain_ssid(ssid);
return ACM_INIT_SSID_ERROR;
}
-
- write_lock(&ssid_list_rwlock);
- list_add(&ssid->node, &ssid_list);
- write_unlock(&ssid_list_rwlock);
printkd("%s: assigned domain %x the ssidref=%x.\n",
__func__, subj->domain_id, ssid->ssidref);
@@ -398,10 +375,6 @@ acm_free_domain_ssid(struct acm_ssid_dom
if (acm_secondary_ops->free_domain_ssid != NULL)
acm_secondary_ops->free_domain_ssid(ssid->secondary_ssid);
ssid->secondary_ssid = NULL;
-
- write_lock(&ssid_list_rwlock);
- list_del(&ssid->node);
- write_unlock(&ssid_list_rwlock);
xfree(ssid);
printkd("%s: Freed individual domain ssid (domain=%02x).\n",
diff -r 07655ed2fe58 -r bf512fde6667 xen/acm/acm_policy.c
--- a/xen/acm/acm_policy.c Thu Jul 26 12:00:32 2007 +0100
+++ b/xen/acm/acm_policy.c Fri Jul 27 09:01:15 2007 +0100
@@ -438,6 +438,10 @@ acm_get_decision(ssidref_t ssidref1, ssi
ret = acm_sharing(ssidref1, ssidref2);
break;
+ case ACMHOOK_authorization:
+ ret = acm_authorization(ssidref1, ssidref2);
+ break;
+
default:
/* deny */
break;
diff -r 07655ed2fe58 -r bf512fde6667 xen/acm/acm_simple_type_enforcement_hooks.c
--- a/xen/acm/acm_simple_type_enforcement_hooks.c Thu Jul 26 12:00:32
2007 +0100
+++ b/xen/acm/acm_simple_type_enforcement_hooks.c Fri Jul 27 09:01:15
2007 +0100
@@ -38,15 +38,16 @@ ssidref_t dom0_ste_ssidref = 0x0001;
/* local cache structures for STE policy */
struct ste_binary_policy ste_bin_pol;
-static inline int have_common_type (ssidref_t ref1, ssidref_t ref2) {
+static inline int have_common_type (ssidref_t ref1, ssidref_t ref2)
+{
int i;
if ( ref1 >= 0 && ref1 < ste_bin_pol.max_ssidrefs &&
ref2 >= 0 && ref2 < ste_bin_pol.max_ssidrefs )
{
for( i = 0; i< ste_bin_pol.max_types; i++ )
- if ( ste_bin_pol.ssidrefs[ref1*ste_bin_pol.max_types + i] &&
- ste_bin_pol.ssidrefs[ref2*ste_bin_pol.max_types + i])
+ if ( ste_bin_pol.ssidrefs[ref1 * ste_bin_pol.max_types + i] &&
+ ste_bin_pol.ssidrefs[ref2 * ste_bin_pol.max_types + i])
{
printkd("%s: common type #%02x.\n", __func__, i);
return 1;
@@ -54,6 +55,26 @@ static inline int have_common_type (ssid
}
return 0;
}
+
+static inline int is_superset(ssidref_t ref1, ssidref_t ref2)
+{
+ int i;
+
+ if ( ref1 >= 0 && ref1 < ste_bin_pol.max_ssidrefs &&
+ ref2 >= 0 && ref2 < ste_bin_pol.max_ssidrefs )
+ {
+ for( i = 0; i< ste_bin_pol.max_types; i++ )
+ if (!ste_bin_pol.ssidrefs[ref1 * ste_bin_pol.max_types + i] &&
+ ste_bin_pol.ssidrefs[ref2 * ste_bin_pol.max_types + i])
+ {
+ return 0;
+ }
+ } else {
+ return 0;
+ }
+ return 1;
+}
+
/* Helper function: return = (subj and obj share a common type) */
static int share_common_type(struct domain *subj, struct domain *obj)
@@ -609,6 +630,7 @@ ste_pre_domain_create(void *subject_ssid
{
/* check for ssidref in range for policy */
ssidref_t ste_ssidref;
+
traceprintk("%s.\n", __func__);
read_lock(&acm_bin_pol_rwlock);
@@ -830,6 +852,15 @@ ste_sharing(ssidref_t ssidref1, ssidref_
GET_SSIDREF(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, ssidref1),
GET_SSIDREF(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, ssidref2));
return (hct ? ACM_ACCESS_PERMITTED : ACM_ACCESS_DENIED);
+}
+
+static int
+ste_authorization(ssidref_t ssidref1, ssidref_t ssidref2)
+{
+ int iss = is_superset(
+ GET_SSIDREF(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, ssidref1),
+ GET_SSIDREF(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, ssidref2));
+ return (iss ? ACM_ACCESS_PERMITTED : ACM_ACCESS_DENIED);
}
static int
@@ -867,6 +898,7 @@ struct acm_operations acm_simple_type_en
.pre_grant_setup = ste_pre_grant_setup,
.fail_grant_setup = NULL,
.sharing = ste_sharing,
+ .authorization = ste_authorization,
.is_default_policy = ste_is_default_policy,
};
diff -r 07655ed2fe58 -r bf512fde6667 xen/include/acm/acm_core.h
--- a/xen/include/acm/acm_core.h Thu Jul 26 12:00:32 2007 +0100
+++ b/xen/include/acm/acm_core.h Fri Jul 27 09:01:15 2007 +0100
@@ -153,8 +153,7 @@ static inline int acm_array_append_tuple
}
/* protos */
-int acm_init_domain_ssid(domid_t id, ssidref_t ssidref);
-int acm_init_domain_ssid_new(struct domain *, ssidref_t ssidref);
+int acm_init_domain_ssid(struct domain *, ssidref_t ssidref);
void acm_free_domain_ssid(struct acm_ssid_domain *ssid);
int acm_init_binary_policy(u32 policy_code);
int acm_set_policy(XEN_GUEST_HANDLE_64(void) buf, u32 buf_size);
diff -r 07655ed2fe58 -r bf512fde6667 xen/include/acm/acm_hooks.h
--- a/xen/include/acm/acm_hooks.h Thu Jul 26 12:00:32 2007 +0100
+++ b/xen/include/acm/acm_hooks.h Fri Jul 27 09:01:15 2007 +0100
@@ -112,7 +112,10 @@ struct acm_operations {
int (*pre_grant_setup) (domid_t id);
void (*fail_grant_setup) (domid_t id);
/* generic domain-requested decision hooks (can be NULL) */
- int (*sharing) (ssidref_t ssidref1, ssidref_t
ssidref2);
+ int (*sharing) (ssidref_t ssidref1,
+ ssidref_t ssidref2);
+ int (*authorization) (ssidref_t ssidref1,
+ ssidref_t ssidref2);
/* determine whether the default policy is installed */
int (*is_default_policy) (void);
};
@@ -148,6 +151,8 @@ static inline int acm_is_policy(char *bu
{ return 0; }
static inline int acm_sharing(ssidref_t ssidref1, ssidref_t ssidref2)
{ return 0; }
+static inline int acm_authorization(ssidref_t ssidref1, ssidref_t ssidref2)
+{ return 0; }
static inline int acm_domain_create(struct domain *d, ssidref_t ssidref)
{ return 0; }
static inline void acm_domain_destroy(struct domain *d)
@@ -157,6 +162,19 @@ static inline void acm_domain_destroy(st
#else
+static inline void acm_domain_ssid_onto_list(struct acm_ssid_domain *ssid)
+{
+ write_lock(&ssid_list_rwlock);
+ list_add(&ssid->node, &ssid_list);
+ write_unlock(&ssid_list_rwlock);
+}
+
+static inline void acm_domain_ssid_off_list(struct acm_ssid_domain *ssid)
+{
+ write_lock(&ssid_list_rwlock);
+ list_del(&ssid->node);
+ write_unlock(&ssid_list_rwlock);
+}
static inline int acm_pre_eventchannel_unbound(domid_t id1, domid_t id2)
{
@@ -241,6 +259,7 @@ static inline void acm_domain_destroy(st
if (acm_secondary_ops->domain_destroy != NULL)
acm_secondary_ops->domain_destroy(ssid, d);
/* free security ssid for the destroyed domain (also if null policy */
+ acm_domain_ssid_off_list(ssid);
acm_free_domain_ssid((struct acm_ssid_domain *)(ssid));
}
}
@@ -250,13 +269,16 @@ static inline int acm_domain_create(stru
{
void *subject_ssid = current->domain->ssid;
domid_t domid = d->domain_id;
- int rc = 0;
+ int rc;
read_lock(&acm_bin_pol_rwlock);
/*
To be called when a domain is created; returns '0' if the
domain is allowed to be created, != '0' if not.
*/
+ rc = acm_init_domain_ssid(d, ssidref);
+ if (rc != ACM_OK)
+ goto error_out;
if ((acm_primary_ops->domain_create != NULL) &&
acm_primary_ops->domain_create(subject_ssid, ssidref, domid)) {
@@ -267,18 +289,17 @@ static inline int acm_domain_create(stru
/* roll-back primary */
if (acm_primary_ops->domain_destroy != NULL)
acm_primary_ops->domain_destroy(d->ssid, d);
+ rc = ACM_ACCESS_DENIED;
+ }
+
+ if ( rc == ACM_OK )
+ {
+ acm_domain_ssid_onto_list(d->ssid);
+ } else {
acm_free_domain_ssid(d->ssid);
- rc = ACM_ACCESS_DENIED;
- }
-
- if (rc == 0) {
- rc = acm_init_domain_ssid_new(d, ssidref);
-
- if (rc != ACM_OK) {
- acm_domain_destroy(d);
- }
- }
-
+ }
+
+error_out:
read_unlock(&acm_bin_pol_rwlock);
return rc;
}
@@ -291,6 +312,19 @@ static inline int acm_sharing(ssidref_t
return ACM_ACCESS_DENIED;
else if ((acm_secondary_ops->sharing != NULL) &&
acm_secondary_ops->sharing(ssidref1, ssidref2)) {
+ return ACM_ACCESS_DENIED;
+ } else
+ return ACM_ACCESS_PERMITTED;
+}
+
+
+static inline int acm_authorization(ssidref_t ssidref1, ssidref_t ssidref2)
+{
+ if ((acm_primary_ops->authorization != NULL) &&
+ acm_primary_ops->authorization(ssidref1, ssidref2))
+ return ACM_ACCESS_DENIED;
+ else if ((acm_secondary_ops->authorization != NULL) &&
+ acm_secondary_ops->authorization(ssidref1, ssidref2)) {
return ACM_ACCESS_DENIED;
} else
return ACM_ACCESS_PERMITTED;
diff -r 07655ed2fe58 -r bf512fde6667 xen/include/public/acm.h
--- a/xen/include/public/acm.h Thu Jul 26 12:00:32 2007 +0100
+++ b/xen/include/public/acm.h Fri Jul 27 09:01:15 2007 +0100
@@ -99,8 +99,9 @@ typedef uint32_t ssidref_t;
typedef uint32_t ssidref_t;
/* hooks that are known to domains */
-#define ACMHOOK_none 0
-#define ACMHOOK_sharing 1
+#define ACMHOOK_none 0
+#define ACMHOOK_sharing 1
+#define ACMHOOK_authorization 2
/* -------security policy relevant type definitions-------- */
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|