--- xen-unstable.hg/tools/python/xen/lowlevel/acm/acm.c | 7 - xen-unstable.hg/tools/python/xen/util/security.py | 22 ++++- xen-unstable.hg/tools/python/xen/xend/XendDomainInfo.py | 10 +- xen-unstable.hg/xen/acm/acm_chinesewall_hooks.c | 1 xen-unstable.hg/xen/acm/acm_core.c | 29 ------ xen-unstable.hg/xen/acm/acm_policy.c | 4 xen-unstable.hg/xen/acm/acm_simple_type_enforcement_hooks.c | 40 ++++++++- xen-unstable.hg/xen/include/acm/acm_core.h | 3 xen-unstable.hg/xen/include/acm/acm_hooks.h | 52 +++++++++--- xen-unstable.hg/xen/include/public/acm.h | 5 - 10 files changed, 122 insertions(+), 51 deletions(-) Index: root/xen-unstable.hg/xen/acm/acm_simple_type_enforcement_hooks.c =================================================================== --- root.orig/xen-unstable.hg/xen/acm/acm_simple_type_enforcement_hooks.c +++ root/xen-unstable.hg/xen/acm/acm_simple_type_enforcement_hooks.c @@ -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; @@ -55,6 +56,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); @@ -833,6 +855,17 @@ ste_sharing(ssidref_t ssidref1, ssidref_ return ACM_ACCESS_DENIED; } +static int +ste_authorization(ssidref_t ssidref1, ssidref_t ssidref2) { + if ( is_superset ( + GET_SSIDREF(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, ssidref1), + GET_SSIDREF(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, ssidref2) + )) + return ACM_ACCESS_PERMITTED; + else + return ACM_ACCESS_DENIED; +} + /* */ static int @@ -870,6 +903,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, }; Index: root/xen-unstable.hg/xen/include/acm/acm_hooks.h =================================================================== --- root.orig/xen-unstable.hg/xen/include/acm/acm_hooks.h +++ root/xen-unstable.hg/xen/include/acm/acm_hooks.h @@ -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); - 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); - } + if ( rc == ACM_OK ) + { + acm_domain_ssid_onto_list(d->ssid); + } else { + acm_free_domain_ssid(d->ssid); } +error_out: read_unlock(&acm_bin_pol_rwlock); return rc; } @@ -297,6 +318,19 @@ static inline int acm_sharing(ssidref_t } +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; +} + + extern int acm_init(char *policy_start, unsigned long policy_len); /* Return true iff buffer has an acm policy magic number. */ Index: root/xen-unstable.hg/xen/acm/acm_core.c =================================================================== --- root.orig/xen-unstable.hg/xen/acm/acm_core.c +++ root/xen-unstable.hg/xen/acm/acm_core.c @@ -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; @@ -374,10 +355,6 @@ int acm_init_domain_ssid_new(struct doma 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); return ACM_OK; @@ -399,10 +376,6 @@ acm_free_domain_ssid(struct acm_ssid_dom 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", __func__, id); Index: root/xen-unstable.hg/xen/include/acm/acm_core.h =================================================================== --- root.orig/xen-unstable.hg/xen/include/acm/acm_core.h +++ root/xen-unstable.hg/xen/include/acm/acm_core.h @@ -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); Index: root/xen-unstable.hg/xen/include/public/acm.h =================================================================== --- root.orig/xen-unstable.hg/xen/include/public/acm.h +++ root/xen-unstable.hg/xen/include/public/acm.h @@ -99,8 +99,9 @@ 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-------- */ Index: root/xen-unstable.hg/xen/acm/acm_policy.c =================================================================== --- root.orig/xen-unstable.hg/xen/acm/acm_policy.c +++ root/xen-unstable.hg/xen/acm/acm_policy.c @@ -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; Index: root/xen-unstable.hg/xen/acm/acm_chinesewall_hooks.c =================================================================== --- root.orig/xen-unstable.hg/xen/acm/acm_chinesewall_hooks.c +++ root/xen-unstable.hg/xen/acm/acm_chinesewall_hooks.c @@ -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, }; Index: root/xen-unstable.hg/tools/python/xen/lowlevel/acm/acm.c =================================================================== --- root.orig/xen-unstable.hg/tools/python/xen/lowlevel/acm/acm.c +++ root/xen-unstable.hg/tools/python/xen/lowlevel/acm/acm.c @@ -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; + uint32_t hooktype; - if (!PyArg_ParseTuple(args, "ssss", &arg1_name, - &arg1, &arg2_name, &arg2)) { + 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); Index: root/xen-unstable.hg/tools/python/xen/util/security.py =================================================================== --- root.orig/xen-unstable.hg/tools/python/xen/util/security.py +++ root/xen-unstable.hg/tools/python/xen/util/security.py @@ -62,6 +62,10 @@ 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.") @@ -463,6 +468,21 @@ def get_decision(arg1, arg2): 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): """ Change the binary policy in the hypervisor Index: root/xen-unstable.hg/tools/python/xen/xend/XendDomainInfo.py =================================================================== --- root.orig/xen-unstable.hg/tools/python/xen/xend/XendDomainInfo.py +++ root/xen-unstable.hg/tools/python/xen/xend/XendDomainInfo.py @@ -1446,9 +1446,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(