ia64/xen-unstable

changeset 15742:f0298301ba8b

acm: Some fixes to the Xend ACM management code

- prevent vlans from being relabeled when they are in use by the
current policy
- fix problems when doing an update of the policy and the name of the
policy changes while doing that
- refactor code that has to take into consideration that unlabeled
domains may be defined using the label __UNLABELED__
- make 'xm list --label' show the complete label of a domain

Signed-off-by: Stefan Berger <stefanb@us.ibm.com>
author kfraser@localhost.localdomain
date Thu Aug 09 16:14:56 2007 +0100 (2007-08-09)
parents 3876b4e7cc0a
children 95f90f24f3b1
files tools/python/xen/util/acmpolicy.py tools/python/xen/util/security.py tools/python/xen/xend/XendDomainInfo.py tools/python/xen/xm/main.py
line diff
     1.1 --- a/tools/python/xen/util/acmpolicy.py	Thu Aug 09 16:02:33 2007 +0100
     1.2 +++ b/tools/python/xen/util/acmpolicy.py	Thu Aug 09 16:14:56 2007 +0100
     1.3 @@ -191,20 +191,21 @@ class ACMPolicy(XSPolicy):
     1.4                   acmpol_old.policy_get_virtualmachinelabel_names_sorted()
     1.5              del_array = ""
     1.6              chg_array = ""
     1.7 +
     1.8              for o in oldvmnames:
     1.9                  if o not in newvmnames:
    1.10 -                    old_idx = oldvmnames.index(o) + 1 # for _NULL_LABEL_
    1.11 +                    old_idx = oldvmnames.index(o)
    1.12                      if vmlabel_map.has_key(o):
    1.13                          #not a deletion, but a renaming
    1.14                          new = vmlabel_map[o]
    1.15 -                        new_idx = newvmnames.index(new) + 1 # for _NULL_LABEL_
    1.16 +                        new_idx = newvmnames.index(new)
    1.17                          chg_array += struct.pack("ii", old_idx, new_idx)
    1.18                      else:
    1.19                          del_array += struct.pack("i", old_idx)
    1.20              for v in newvmnames:
    1.21                  if v in oldvmnames:
    1.22 -                    old_idx = oldvmnames.index(v) + 1 # for _NULL_LABEL_
    1.23 -                    new_idx = newvmnames.index(v) + 1 # for _NULL_LABEL_
    1.24 +                    old_idx = oldvmnames.index(v)
    1.25 +                    new_idx = newvmnames.index(v)
    1.26                      if old_idx != new_idx:
    1.27                          chg_array += struct.pack("ii", old_idx, new_idx)
    1.28  
    1.29 @@ -348,7 +349,7 @@ class ACMPolicy(XSPolicy):
    1.30          ssidref = xsconstants.INVALID_SSIDREF
    1.31          names = self.policy_get_virtualmachinelabel_names_sorted()
    1.32          try:
    1.33 -            vmidx = names.index(vm_label) + 1 # for _NULL_LABEL_
    1.34 +            vmidx = names.index(vm_label)
    1.35              ssidref = (vmidx << 16) | vmidx
    1.36          except:
    1.37              pass
    1.38 @@ -618,6 +619,9 @@ class ACMPolicy(XSPolicy):
    1.39          vmnames.remove(bootstrap)
    1.40          vmnames.sort()
    1.41          vmnames.insert(0, bootstrap)
    1.42 +        if ACM_LABEL_UNLABELED in vmnames:
    1.43 +            vmnames.remove(ACM_LABEL_UNLABELED)
    1.44 +            vmnames.insert(0, ACM_LABEL_UNLABELED)
    1.45          return vmnames
    1.46  
    1.47      def policy_get_virtualmachinelabel_names_sorted(self):
    1.48 @@ -625,7 +629,10 @@ class ACMPolicy(XSPolicy):
    1.49              label will be the first one in that list, followed
    1.50              by an alphabetically sorted list of VM label names """
    1.51          vmnames = self.policy_get_virtualmachinelabel_names()
    1.52 -        return self.policy_sort_virtualmachinelabel_names(vmnames)
    1.53 +        res = self.policy_sort_virtualmachinelabel_names(vmnames)
    1.54 +        if res[0] != ACM_LABEL_UNLABELED:
    1.55 +            res.insert(0, ACM_LABEL_UNLABELED)
    1.56 +        return res
    1.57  
    1.58      def policy_get_virtualmachinelabels(self):
    1.59          """ Get a list of all virtual machine labels in this policy """
    1.60 @@ -906,7 +913,7 @@ class ACMPolicy(XSPolicy):
    1.61              allvmtypes = self.policy_get_virtualmachinelabel_names_sorted()
    1.62          except:
    1.63              return None
    1.64 -        return allvmtypes[chwall_ref-1] # skip _NULL_LABEL_
    1.65 +        return allvmtypes[chwall_ref]
    1.66  
    1.67      def policy_get_domain_label_formatted(self, domid):
    1.68          label = self.policy_get_domain_label(domid)
     2.1 --- a/tools/python/xen/util/security.py	Thu Aug 09 16:02:33 2007 +0100
     2.2 +++ b/tools/python/xen/util/security.py	Thu Aug 09 16:14:56 2007 +0100
     2.3 @@ -838,13 +838,28 @@ def set_resource_label_xapi(resource, re
     2.4  
     2.5  
     2.6  def is_resource_in_use(resource):
     2.7 -    """ Investigate all running domains whether they use this device """
     2.8 +    """
     2.9 +       Domain-0 'owns' resources of type 'VLAN', the rest are owned by
    2.10 +       the guests.
    2.11 +    """
    2.12      from xen.xend import XendDomain
    2.13 -    dominfos = XendDomain.instance().list('all')
    2.14      lst = []
    2.15 -    for dominfo in dominfos:
    2.16 -        if is_resource_in_use_by_dom(dominfo, resource):
    2.17 -            lst.append(dominfo)
    2.18 +    if resource.startswith('vlan'):
    2.19 +        from xen.xend.XendXSPolicyAdmin import XSPolicyAdminInstance
    2.20 +        curpol = XSPolicyAdminInstance().get_loaded_policy()
    2.21 +        policytype, label, policy = get_res_label(resource)
    2.22 +        if curpol and \
    2.23 +           policytype == xsconstants.ACM_POLICY_ID and \
    2.24 +           policy == curpol.get_name() and \
    2.25 +           label in curpol.policy_get_resourcelabel_names():
    2.26 +            # VLAN is in use.
    2.27 +            lst.append(XendDomain.instance().
    2.28 +                         get_vm_by_uuid(XendDomain.DOM0_UUID))
    2.29 +    else:
    2.30 +        dominfos = XendDomain.instance().list('all')
    2.31 +        for dominfo in dominfos:
    2.32 +            if is_resource_in_use_by_dom(dominfo, resource):
    2.33 +                lst.append(dominfo)
    2.34      return lst
    2.35  
    2.36  def devices_equal(res1, res2, mustexist=True):
    2.37 @@ -892,6 +907,10 @@ def get_domain_resources(dominfo):
    2.38              if sec_lab:
    2.39                  resources[typ].append(sec_lab)
    2.40              else:
    2.41 +                # !!! This should really get the label of the domain
    2.42 +                # or at least a resource label that has the same STE type
    2.43 +                # as the domain has
    2.44 +                from xen.util.acmpolicy import ACM_LABEL_UNLABELED
    2.45                  resources[typ].append("%s:%s:%s" %
    2.46                                        (xsconstants.ACM_POLICY_ID,
    2.47                                         active_policy,
    2.48 @@ -924,7 +943,8 @@ def resources_compatible_with_vmlabel(xs
    2.49  
    2.50  
    2.51  def __resources_compatible_with_vmlabel(xspol, dominfo, vmlabel,
    2.52 -                                        access_control):
    2.53 +                                        access_control,
    2.54 +                                        is_policy_update=False):
    2.55      """
    2.56          Check whether the resources' labels are compatible with the
    2.57          given VM label. The access_control parameter provides a
    2.58 @@ -955,15 +975,23 @@ def __resources_compatible_with_vmlabel(
    2.59          elif key in [ 'vif' ]:
    2.60              for xapi_label in value:
    2.61                  label = xapi_label.split(":")
    2.62 -                if not collect_labels(reslabels, label, polname):
    2.63 -                    return False
    2.64 +                from xen.util.acmpolicy import ACM_LABEL_UNLABELED
    2.65 +                if not (is_policy_update and \
    2.66 +                        label[2] == ACM_LABEL_UNLABELED):
    2.67 +                    if not collect_labels(reslabels, label, polname):
    2.68 +                        return False
    2.69          else:
    2.70              log.error("Unhandled device type: %s" % key)
    2.71              return False
    2.72  
    2.73      # Check that all resource labes have a common STE type with the
    2.74      # vmlabel
    2.75 -    rc = xspol.policy_check_vmlabel_against_reslabels(vmlabel, reslabels)
    2.76 +    if len(reslabels) > 0:
    2.77 +        rc = xspol.policy_check_vmlabel_against_reslabels(vmlabel, reslabels)
    2.78 +    else:
    2.79 +        rc = True
    2.80 +    log.info("vmlabel=%s, reslabels=%s, rc=%s" %
    2.81 +             (vmlabel, reslabels, str(rc)))
    2.82      return rc;
    2.83  
    2.84  def set_resource_label(resource, policytype, policyref, reslabel, \
    2.85 @@ -1234,11 +1262,12 @@ def change_acm_policy(bin_pol, del_array
    2.86                  compatible = __resources_compatible_with_vmlabel(new_acmpol,
    2.87                                                        dominfo,
    2.88                                                        new_vmlabel,
    2.89 -                                                      access_control)
    2.90 +                                                      access_control,
    2.91 +                                                      is_policy_update=True)
    2.92                  log.info("Domain %s with new label '%s' can access its "
    2.93                           "resources? : %s" %
    2.94                           (name, new_vmlabel, str(compatible)))
    2.95 -                log.info("VM labels in new domain: %s" %
    2.96 +                log.info("VM labels in new policy: %s" %
    2.97                           new_acmpol.policy_get_virtualmachinelabel_names())
    2.98                  if not compatible:
    2.99                      return (-xsconstants.XSERR_RESOURCE_ACCESS, "")
   2.100 @@ -1252,11 +1281,16 @@ def change_acm_policy(bin_pol, del_array
   2.101                  sec_lab, new_seclab = labels
   2.102                  if sec_lab != new_seclab:
   2.103                      log.info("Updating domain %s to new label '%s'." % \
   2.104 -                             (sec_lab, new_seclab))
   2.105 +                             (dominfo.getName(), new_seclab))
   2.106                      # This better be working!
   2.107 -                    dominfo.set_security_label(new_seclab,
   2.108 -                                               sec_lab,
   2.109 -                                               new_acmpol)
   2.110 +                    res = dominfo.set_security_label(new_seclab,
   2.111 +                                                     sec_lab,
   2.112 +                                                     new_acmpol,
   2.113 +                                                     cur_acmpol)
   2.114 +                    if res[0] != xsconstants.XSERR_SUCCESS:
   2.115 +                        log.info("ERROR: Could not chg label on domain %s: %s" %
   2.116 +                                 (dominfo.getName(),
   2.117 +                                  xsconstants.xserr2string(-int(res[0]))))
   2.118      finally:
   2.119          log.info("----------------------------------------------")
   2.120          mapfile_unlock()
     3.1 --- a/tools/python/xen/xend/XendDomainInfo.py	Thu Aug 09 16:02:33 2007 +0100
     3.2 +++ b/tools/python/xen/xend/XendDomainInfo.py	Thu Aug 09 16:14:56 2007 +0100
     3.3 @@ -2187,11 +2187,18 @@ class XendDomainInfo:
     3.4          return self.metrics.get_uuid();
     3.5  
     3.6  
     3.7 -    def get_security_label(self):
     3.8 +    def get_security_label(self, xspol=None):
     3.9 +        """
    3.10 +           Get the security label of a domain
    3.11 +           @param xspol   The policy to use when converting the ssid into
    3.12 +                          a label; only to be passed during the updating
    3.13 +                          of the policy
    3.14 +        """
    3.15          domid = self.getDomid()
    3.16  
    3.17 -        from xen.xend.XendXSPolicyAdmin import XSPolicyAdminInstance
    3.18 -        xspol = XSPolicyAdminInstance().get_loaded_policy()
    3.19 +        if not xspol:
    3.20 +            from xen.xend.XendXSPolicyAdmin import XSPolicyAdminInstance
    3.21 +            xspol = XSPolicyAdminInstance().get_loaded_policy()
    3.22  
    3.23          if domid == 0:
    3.24              if xspol:
    3.25 @@ -2202,7 +2209,8 @@ class XendDomainInfo:
    3.26              label = self.info.get('security_label', '')
    3.27          return label
    3.28  
    3.29 -    def set_security_label(self, seclab, old_seclab, xspol=None):
    3.30 +    def set_security_label(self, seclab, old_seclab, xspol=None,
    3.31 +                           xspol_old=None):
    3.32          """
    3.33             Set the security label of a domain from its old to
    3.34             a new value.
    3.35 @@ -2213,6 +2221,8 @@ class XendDomainInfo:
    3.36             @param xspol   An optional policy under which this
    3.37                            update should be done. If not given,
    3.38                            then the current active policy is used.
    3.39 +           @param xspol_old The old policy; only to be passed during
    3.40 +                           the updating of a policy
    3.41             @return Returns return code, a string with errors from
    3.42                     the hypervisor's operation, old label of the
    3.43                     domain
    3.44 @@ -2223,6 +2233,7 @@ class XendDomainInfo:
    3.45          new_ssidref = 0
    3.46          domid = self.getDomid()
    3.47          res_labels = None
    3.48 +        is_policy_update = (xspol_old != None)
    3.49  
    3.50          from xen.xend.XendXSPolicyAdmin import XSPolicyAdminInstance
    3.51          from xen.util import xsconstants
    3.52 @@ -2276,13 +2287,16 @@ class XendDomainInfo:
    3.53  
    3.54                  # Check that all used resources are accessible under the
    3.55                  # new label
    3.56 -                if not security.resources_compatible_with_vmlabel(xspol,
    3.57 +                if not is_policy_update and \
    3.58 +                   not security.resources_compatible_with_vmlabel(xspol,
    3.59                            self, label):
    3.60                      return (-xsconstants.XSERR_BAD_LABEL, "", "", 0)
    3.61  
    3.62                  #Check label against expected one.
    3.63 -                old_label = self.get_security_label()
    3.64 +                old_label = self.get_security_label(xspol_old)
    3.65                  if old_label != old_seclab:
    3.66 +                    log.info("old_label != old_seclab: %s != %s" %
    3.67 +                             (old_label, old_seclab))
    3.68                      return (-xsconstants.XSERR_BAD_LABEL, "", "", 0)
    3.69  
    3.70                  # relabel domain in the hypervisor
     4.1 --- a/tools/python/xen/xm/main.py	Thu Aug 09 16:02:33 2007 +0100
     4.2 +++ b/tools/python/xen/xm/main.py	Thu Aug 09 16:14:56 2007 +0100
     4.3 @@ -876,7 +876,7 @@ def parse_doms_info(info):
     4.4      if len(tmp) != 3:
     4.5          seclabel = ""
     4.6      else:
     4.7 -        seclabel = tmp[2]
     4.8 +        seclabel = security_label
     4.9      parsed_info['seclabel'] = seclabel
    4.10  
    4.11      if serverType == SERVER_XEN_API: