use independent decryption contexts for backup files
authorPhilipp Gesang <philipp.gesang@intra2net.com>
Thu, 4 May 2017 12:24:06 +0000 (14:24 +0200)
committerThomas Jarosch <thomas.jarosch@intra2net.com>
Mon, 2 Apr 2018 11:34:08 +0000 (13:34 +0200)
When restoring individual files from a diff backup, Deltatar will
traverse both tarballs simultaneously. This leads to access
patterns where reads are interleaved between the two sources,
possibly corrupting the decryption state. Thus when restoring
from multiple “index files” (in practice only two are relevant),
use a separate decryptor context for each of them.

deltatar/deltatar.py

index 27c0630..2dcb6ee 100644 (file)
@@ -1064,11 +1064,14 @@ class DeltaTar(object):
                 Allows this iterator to be used with the "with" statement
                 '''
                 if self.tar_obj is None:
+                    decryptor = None
+                    if self.delta_tar.password is not None:
+                        decryptor = crypto.Decrypt (self.delta_tar.password)
                     self.tar_obj = tarfile.TarFile.open(self.tar_path,
                         mode='r' + self.delta_tar.mode,
                         format=tarfile.GNU_FORMAT,
                         concat='#' in self.delta_tar.mode,
-                        encryption=self.delta_tar.decryptor,
+                        encryption=decryptor,
                         new_volume_handler=self.new_volume_handler,
                         save_to_members=False,
                         dereference=True)
@@ -1468,6 +1471,7 @@ class RestoreHelper(object):
         self._directories = []
         self._deltatar = deltatar
         self._cwd = cwd
+        self.password = deltatar.password
 
         try:
             import grp, pwd
@@ -1483,6 +1487,10 @@ class RestoreHelper(object):
             for index in index_list:
                 is_full = index == index_list[-1]
 
+                decryptor = None
+                if self.password is not None:
+                    decryptor = crypto.Decrypt (self.password)
+
                 # make paths absolute to avoid cwd problems
                 if not os.path.isabs(index):
                     index = os.path.normpath(os.path.join(cwd, index))
@@ -1499,7 +1507,8 @@ class RestoreHelper(object):
                     last_lno = 0,
                     new_volume_handler = partial(self.new_volume_handler,
                         self._deltatar, self._cwd, is_full,
-                        os.path.dirname(index), self._deltatar.decryptor)
+                        os.path.dirname(index), decryptor),
+                    decryptor = decryptor
                 )
                 self._data.append(s)
         else:
@@ -1521,7 +1530,8 @@ class RestoreHelper(object):
                 iterator = None,
                 last_itelement = None,
                 last_lno = 0,
-                new_volume_handler = tarobj.new_volume_handler
+                new_volume_handler = tarobj.new_volume_handler,
+                decryptor = self._deltatar.decryptor
             )
             self._data.append(s)
 
@@ -1769,7 +1779,7 @@ class RestoreHelper(object):
                     fileobj=index_data['vol_fd'],
                     format=tarfile.GNU_FORMAT,
                     concat='#' in self._deltatar.mode,
-                    encryption=self._deltatar.decryptor,
+                    encryption=index_data["decryptor"],
                     new_volume_handler=index_data['new_volume_handler'],
                     save_to_members=False)