--- xen-unstable.hg/tools/python/xen/util/acmpolicy.py | 21 +++-- xen-unstable.hg/tools/python/xen/util/security.py | 64 ++++++++++++---- xen-unstable.hg/tools/python/xen/xend/XendDomainInfo.py | 26 +++++- xen-unstable.hg/tools/python/xen/xm/main.py | 2 4 files changed, 84 insertions(+), 29 deletions(-) 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 @@ -838,13 +838,28 @@ def set_resource_label_xapi(resource, re def is_resource_in_use(resource): - """ Investigate all running domains whether they use this device """ + """ + Domain-0 'owns' resources of type 'VLAN', the rest are owned by + the guests. + """ from xen.xend import XendDomain - dominfos = XendDomain.instance().list('all') lst = [] - for dominfo in dominfos: - if is_resource_in_use_by_dom(dominfo, resource): - lst.append(dominfo) + if resource.startswith('vlan'): + from xen.xend.XendXSPolicyAdmin import XSPolicyAdminInstance + curpol = XSPolicyAdminInstance().get_loaded_policy() + policytype, label, policy = get_res_label(resource) + if curpol and \ + policytype == xsconstants.ACM_POLICY_ID and \ + policy == curpol.get_name() and \ + label in curpol.policy_get_resourcelabel_names(): + # VLAN is in use. + lst.append(XendDomain.instance(). + get_vm_by_uuid(XendDomain.DOM0_UUID)) + else: + dominfos = XendDomain.instance().list('all') + for dominfo in dominfos: + if is_resource_in_use_by_dom(dominfo, resource): + lst.append(dominfo) return lst def devices_equal(res1, res2, mustexist=True): @@ -892,6 +907,10 @@ def get_domain_resources(dominfo): if sec_lab: resources[typ].append(sec_lab) else: + # !!! This should really get the label of the domain + # or at least a resource label that has the same STE type + # as the domain has + from xen.util.acmpolicy import ACM_LABEL_UNLABELED resources[typ].append("%s:%s:%s" % (xsconstants.ACM_POLICY_ID, active_policy, @@ -924,7 +943,8 @@ def resources_compatible_with_vmlabel(xs def __resources_compatible_with_vmlabel(xspol, dominfo, vmlabel, - access_control): + access_control, + is_policy_update=False): """ Check whether the resources' labels are compatible with the given VM label. The access_control parameter provides a @@ -955,15 +975,23 @@ def __resources_compatible_with_vmlabel( elif key in [ 'vif' ]: for xapi_label in value: label = xapi_label.split(":") - if not collect_labels(reslabels, label, polname): - return False + from xen.util.acmpolicy import ACM_LABEL_UNLABELED + if not (is_policy_update and \ + label[2] == ACM_LABEL_UNLABELED): + if not collect_labels(reslabels, label, polname): + return False else: log.error("Unhandled device type: %s" % key) return False # Check that all resource labes have a common STE type with the # vmlabel - rc = xspol.policy_check_vmlabel_against_reslabels(vmlabel, reslabels) + if len(reslabels) > 0: + rc = xspol.policy_check_vmlabel_against_reslabels(vmlabel, reslabels) + else: + rc = True + log.info("vmlabel=%s, reslabels=%s, rc=%s" % + (vmlabel, reslabels, str(rc))) return rc; def set_resource_label(resource, policytype, policyref, reslabel, \ @@ -1234,11 +1262,12 @@ def change_acm_policy(bin_pol, del_array compatible = __resources_compatible_with_vmlabel(new_acmpol, dominfo, new_vmlabel, - access_control) + access_control, + is_policy_update=True) log.info("Domain %s with new label '%s' can access its " "resources? : %s" % (name, new_vmlabel, str(compatible))) - log.info("VM labels in new domain: %s" % + log.info("VM labels in new policy: %s" % new_acmpol.policy_get_virtualmachinelabel_names()) if not compatible: return (-xsconstants.XSERR_RESOURCE_ACCESS, "") @@ -1252,11 +1281,16 @@ def change_acm_policy(bin_pol, del_array sec_lab, new_seclab = labels if sec_lab != new_seclab: log.info("Updating domain %s to new label '%s'." % \ - (sec_lab, new_seclab)) + (dominfo.getName(), new_seclab)) # This better be working! - dominfo.set_security_label(new_seclab, - sec_lab, - new_acmpol) + res = dominfo.set_security_label(new_seclab, + sec_lab, + new_acmpol, + cur_acmpol) + if res[0] != xsconstants.XSERR_SUCCESS: + log.info("ERROR: Could not chg label on domain %s: %s" % + (dominfo.getName(), + xsconstants.xserr2string(-int(res[0])))) finally: log.info("----------------------------------------------") mapfile_unlock() Index: root/xen-unstable.hg/tools/python/xen/util/acmpolicy.py =================================================================== --- root.orig/xen-unstable.hg/tools/python/xen/util/acmpolicy.py +++ root/xen-unstable.hg/tools/python/xen/util/acmpolicy.py @@ -191,20 +191,21 @@ class ACMPolicy(XSPolicy): acmpol_old.policy_get_virtualmachinelabel_names_sorted() del_array = "" chg_array = "" + for o in oldvmnames: if o not in newvmnames: - old_idx = oldvmnames.index(o) + 1 # for _NULL_LABEL_ + old_idx = oldvmnames.index(o) if vmlabel_map.has_key(o): #not a deletion, but a renaming new = vmlabel_map[o] - new_idx = newvmnames.index(new) + 1 # for _NULL_LABEL_ + new_idx = newvmnames.index(new) chg_array += struct.pack("ii", old_idx, new_idx) else: del_array += struct.pack("i", old_idx) for v in newvmnames: if v in oldvmnames: - old_idx = oldvmnames.index(v) + 1 # for _NULL_LABEL_ - new_idx = newvmnames.index(v) + 1 # for _NULL_LABEL_ + old_idx = oldvmnames.index(v) + new_idx = newvmnames.index(v) if old_idx != new_idx: chg_array += struct.pack("ii", old_idx, new_idx) @@ -348,7 +349,7 @@ class ACMPolicy(XSPolicy): ssidref = xsconstants.INVALID_SSIDREF names = self.policy_get_virtualmachinelabel_names_sorted() try: - vmidx = names.index(vm_label) + 1 # for _NULL_LABEL_ + vmidx = names.index(vm_label) ssidref = (vmidx << 16) | vmidx except: pass @@ -618,6 +619,9 @@ class ACMPolicy(XSPolicy): vmnames.remove(bootstrap) vmnames.sort() vmnames.insert(0, bootstrap) + if ACM_LABEL_UNLABELED in vmnames: + vmnames.remove(ACM_LABEL_UNLABELED) + vmnames.insert(0, ACM_LABEL_UNLABELED) return vmnames def policy_get_virtualmachinelabel_names_sorted(self): @@ -625,7 +629,10 @@ class ACMPolicy(XSPolicy): label will be the first one in that list, followed by an alphabetically sorted list of VM label names """ vmnames = self.policy_get_virtualmachinelabel_names() - return self.policy_sort_virtualmachinelabel_names(vmnames) + res = self.policy_sort_virtualmachinelabel_names(vmnames) + if res[0] != ACM_LABEL_UNLABELED: + res.insert(0, ACM_LABEL_UNLABELED) + return res def policy_get_virtualmachinelabels(self): """ Get a list of all virtual machine labels in this policy """ @@ -906,7 +913,7 @@ class ACMPolicy(XSPolicy): allvmtypes = self.policy_get_virtualmachinelabel_names_sorted() except: return None - return allvmtypes[chwall_ref-1] # skip _NULL_LABEL_ + return allvmtypes[chwall_ref] def policy_get_domain_label_formatted(self, domid): label = self.policy_get_domain_label(domid) 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 @@ -2197,11 +2197,18 @@ class XendDomainInfo: return self.metrics.get_uuid(); - def get_security_label(self): + def get_security_label(self, xspol=None): + """ + Get the security label of a domain + @param xspol The policy to use when converting the ssid into + a label; only to be passed during the updating + of the policy + """ domid = self.getDomid() - from xen.xend.XendXSPolicyAdmin import XSPolicyAdminInstance - xspol = XSPolicyAdminInstance().get_loaded_policy() + if not xspol: + from xen.xend.XendXSPolicyAdmin import XSPolicyAdminInstance + xspol = XSPolicyAdminInstance().get_loaded_policy() if domid == 0: if xspol: @@ -2212,7 +2219,8 @@ class XendDomainInfo: label = self.info.get('security_label', '') return label - def set_security_label(self, seclab, old_seclab, xspol=None): + def set_security_label(self, seclab, old_seclab, xspol=None, + xspol_old=None): """ Set the security label of a domain from its old to a new value. @@ -2223,6 +2231,8 @@ class XendDomainInfo: @param xspol An optional policy under which this update should be done. If not given, then the current active policy is used. + @param xspol_old The old policy; only to be passed during + the updating of a policy @return Returns return code, a string with errors from the hypervisor's operation, old label of the domain @@ -2233,6 +2243,7 @@ class XendDomainInfo: new_ssidref = 0 domid = self.getDomid() res_labels = None + is_policy_update = (xspol_old != None) from xen.xend.XendXSPolicyAdmin import XSPolicyAdminInstance from xen.util import xsconstants @@ -2286,13 +2297,16 @@ class XendDomainInfo: # Check that all used resources are accessible under the # new label - if not security.resources_compatible_with_vmlabel(xspol, + if not is_policy_update and \ + not security.resources_compatible_with_vmlabel(xspol, self, label): return (-xsconstants.XSERR_BAD_LABEL, "", "", 0) #Check label against expected one. - old_label = self.get_security_label() + old_label = self.get_security_label(xspol_old) if old_label != old_seclab: + log.info("old_label != old_seclab: %s != %s" % + (old_label, old_seclab)) return (-xsconstants.XSERR_BAD_LABEL, "", "", 0) # relabel domain in the hypervisor Index: root/xen-unstable.hg/tools/python/xen/xm/main.py =================================================================== --- root.orig/xen-unstable.hg/tools/python/xen/xm/main.py +++ root/xen-unstable.hg/tools/python/xen/xm/main.py @@ -876,7 +876,7 @@ def parse_doms_info(info): if len(tmp) != 3: seclabel = "" else: - seclabel = tmp[2] + seclabel = security_label parsed_info['seclabel'] = seclabel if serverType == SERVER_XEN_API: