xend, security: Prevent changing of the policy while VMs are migrating
authorKeir Fraser <keir.fraser@citrix.com>
Wed, 5 Nov 2008 10:23:26 +0000 (10:23 +0000)
committerKeir Fraser <keir.fraser@citrix.com>
Wed, 5 Nov 2008 10:23:26 +0000 (10:23 +0000)
The net changes of this patch are that the reader-side lock is put
into the path of the migration code and the writer lock into the path
of the code that handles the changing of the policy. Simultaneous
migrations of multiple hosts still work after this lock has been added.

Signed-off-by: Stefan Berger <stefanb@us.ibm.com>
tools/python/xen/xend/XendDomain.py
tools/python/xen/xend/XendDomainInfo.py

index 9faebe95aaa0ff0663f481de92d8e3cdb1f9b058..d5195c421e4c34f9ef2540bfecc11c9d541cdb90 100644 (file)
@@ -50,7 +50,7 @@ from xen.xend.XendAPIConstants import *
 
 from xen.xend.xenstore.xstransact import xstransact
 from xen.xend.xenstore.xswatch import xswatch
-from xen.util import mkdir
+from xen.util import mkdir, rwlock
 from xen.xend import uuid
 
 xc = xen.lowlevel.xc.xc()
@@ -93,6 +93,8 @@ class XendDomain:
         self.managed_domains = {}
         self.domains_lock = threading.RLock()
 
+        self.policy_lock = rwlock.RWLock()
+
         # xen api instance vars
         # TODO: nothing uses this at the moment
         self._allow_new_domains = True
@@ -1139,16 +1141,21 @@ class XendDomain:
         """
 
         try:
-            return XendCheckpoint.restore(self, fd, paused=paused, relocating=relocating)
-        except XendError, e:
-            log.exception("Restore failed")
-            raise
-        except:
-            # I don't really want to log this exception here, but the error
-            # handling in the relocation-socket handling code (relocate.py) is
-            # poor, so we need to log this for debugging.
-            log.exception("Restore failed")
-            raise XendError("Restore failed")
+            self.policy_lock.acquire_reader()
+
+            try:
+                return XendCheckpoint.restore(self, fd, paused=paused, relocating=relocating)
+            except XendError, e:
+                log.exception("Restore failed")
+                raise
+            except:
+                # I don't really want to log this exception here, but the error
+                # handling in the relocation-socket handling code (relocate.py) is
+                # poor, so we need to log this for debugging.
+                log.exception("Restore failed")
+                raise XendError("Restore failed")
+        finally:
+            self.policy_lock.release()
  
     def domain_unpause(self, domid):
         """Unpause domain execution.
index d0ade8c858d835f53c80a8e2e697bb3773bf08c1..e8a94f1d2fd0acbf7749e15663a78b192ccddc3d 100644 (file)
@@ -3011,64 +3011,69 @@ class XendDomainInfo:
         if not xspol:
             xspol = poladmin.get_policy_by_name(policy)
 
-        if state in [ DOM_STATE_RUNNING, DOM_STATE_PAUSED ]:
-            #if domain is running or paused try to relabel in hypervisor
-            if not xspol:
-                return (-xsconstants.XSERR_POLICY_NOT_LOADED, "", "", 0)
-
-            if typ != xspol.get_type_name() or \
-               policy != xspol.get_name():
-                return (-xsconstants.XSERR_BAD_LABEL, "", "", 0)
-
-            if typ == xsconstants.ACM_POLICY_ID:
-                new_ssidref = xspol.vmlabel_to_ssidref(label)
-                if new_ssidref == xsconstants.INVALID_SSIDREF:
-                    return (-xsconstants.XSERR_BAD_LABEL, "", "", 0)
+        try:
+            xen.xend.XendDomain.instance().policy_lock.acquire_writer()
 
-                # Check that all used resources are accessible under the
-                # new label
-                if not is_policy_update and \
-                   not security.resources_compatible_with_vmlabel(xspol,
-                          self, label):
+            if state in [ DOM_STATE_RUNNING, DOM_STATE_PAUSED ]:
+                #if domain is running or paused try to relabel in hypervisor
+                if not xspol:
+                    return (-xsconstants.XSERR_POLICY_NOT_LOADED, "", "", 0)
+
+                if typ != xspol.get_type_name() or \
+                   policy != xspol.get_name():
                     return (-xsconstants.XSERR_BAD_LABEL, "", "", 0)
 
-                #Check label against expected one. Can only do this
-                # if the policy hasn't changed underneath in the meantime
-                if xspol_old == None:
-                    old_label = self.get_security_label()
-                    if old_label != old_seclab:
-                        log.info("old_label != old_seclab: %s != %s" %
-                                 (old_label, old_seclab))
+                if typ == xsconstants.ACM_POLICY_ID:
+                    new_ssidref = xspol.vmlabel_to_ssidref(label)
+                    if new_ssidref == xsconstants.INVALID_SSIDREF:
                         return (-xsconstants.XSERR_BAD_LABEL, "", "", 0)
 
-                # relabel domain in the hypervisor
-                rc, errors = security.relabel_domains([[domid, new_ssidref]])
-                log.info("rc from relabeling in HV: %d" % rc)
-            else:
-                return (-xsconstants.XSERR_POLICY_TYPE_UNSUPPORTED, "", "", 0)
+                    # Check that all used resources are accessible under the
+                    # new label
+                    if not is_policy_update and \
+                       not security.resources_compatible_with_vmlabel(xspol,
+                              self, label):
+                        return (-xsconstants.XSERR_BAD_LABEL, "", "", 0)
 
-        if rc == 0:
-            # HALTED, RUNNING or PAUSED
-            if domid == 0:
-                if xspol:
-                    self.info['security_label'] = seclab
-                    ssidref = poladmin.set_domain0_bootlabel(xspol, label)
+                    #Check label against expected one. Can only do this
+                    # if the policy hasn't changed underneath in the meantime
+                    if xspol_old == None:
+                        old_label = self.get_security_label()
+                        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
+                    rc, errors = security.relabel_domains([[domid, new_ssidref]])
+                    log.info("rc from relabeling in HV: %d" % rc)
                 else:
-                    return (-xsconstants.XSERR_POLICY_NOT_LOADED, "", "", 0)
-            else:
-                if self.info.has_key('security_label'):
-                    old_label = self.info['security_label']
-                    # Check label against expected one, unless wildcard
-                    if old_label != old_seclab:
-                        return (-xsconstants.XSERR_BAD_LABEL, "", "", 0)
+                    return (-xsconstants.XSERR_POLICY_TYPE_UNSUPPORTED, "", "", 0)
+
+            if rc == 0:
+                # HALTED, RUNNING or PAUSED
+                if domid == 0:
+                    if xspol:
+                        self.info['security_label'] = seclab
+                        ssidref = poladmin.set_domain0_bootlabel(xspol, label)
+                    else:
+                        return (-xsconstants.XSERR_POLICY_NOT_LOADED, "", "", 0)
+                else:
+                    if self.info.has_key('security_label'):
+                        old_label = self.info['security_label']
+                        # Check label against expected one, unless wildcard
+                        if old_label != old_seclab:
+                            return (-xsconstants.XSERR_BAD_LABEL, "", "", 0)
 
-                self.info['security_label'] = seclab
+                    self.info['security_label'] = seclab
 
-                try:
-                    xen.xend.XendDomain.instance().managed_config_save(self)
-                except:
-                    pass
-        return (rc, errors, old_label, new_ssidref)
+                    try:
+                        xen.xend.XendDomain.instance().managed_config_save(self)
+                    except:
+                        pass
+            return (rc, errors, old_label, new_ssidref)
+        finally:
+            xen.xend.XendDomain.instance().policy_lock.release()
 
     def get_on_shutdown(self):
         after_shutdown = self.info.get('actions_after_shutdown')