From f7f1038f5724667c7cc141eba75ef678ec113592 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Marczykowski-G=C3=B3recki?= Date: Wed, 10 Feb 2016 16:55:25 +0100 Subject: [PATCH] core: add a stopgap detection for simultaneous qubes.xml access For now simply throw an exception. Proper solution require some locking QubesOS/qubes-issues#1729 --- qubes/__init__.py | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/qubes/__init__.py b/qubes/__init__.py index 2a2fae84..1bfb3599 100644 --- a/qubes/__init__.py +++ b/qubes/__init__.py @@ -1184,6 +1184,8 @@ class Qubes(PropertyHolder): super(Qubes, self).__init__(xml=None, **kwargs) + self.__load_timestamp = None + if load: self.load() @@ -1261,6 +1263,9 @@ class Qubes(PropertyHolder): vm.events_enabled = True vm.fire_event('domain-loaded') + # get a file timestamp (before closing it - still holding the lock!), + # to detect whether anyone else have modified it in the meantime + self.__load_timestamp = os.path.getmtime(self._store) # intentionally do not call explicit unlock fh.close() del fh @@ -1287,7 +1292,7 @@ class Qubes(PropertyHolder): mitigated: - Running out of disk space. No space left should not result in empty - file. This is done by writing to temporary file and the renaming. + file. This is done by writing to temporary file and then renaming. - Attempts to write two or more files concurrently. This is done by sophisticated locking. @@ -1313,6 +1318,13 @@ class Qubes(PropertyHolder): else: os.close(fd_old) + if self.__load_timestamp: + current_file_timestamp = os.path.getmtime(self._store) + if current_file_timestamp != self.__load_timestamp: + os.close(fd_old) + raise qubes.exc.QubesException( + "Someone else modified qubes.xml in the meantime") + fh_new = tempfile.NamedTemporaryFile(prefix=self._store, delete=False) lxml.etree.ElementTree(self.__xml__()).write( fh_new, encoding='utf-8', pretty_print=True) @@ -1324,6 +1336,9 @@ class Qubes(PropertyHolder): # intentionally do not call explicit unlock to not unlock the file # before all buffers are flushed fh_new.close() + # update stored mtime, in case of multiple save() calls without + # loading qubes.xml again + self.__load_timestamp = os.path.getmtime(self._store) os.close(fd_old)