瀏覽代碼

Merge pull request #6771 from ThomasWaldmann/safe-secure-erase-1.1

secure_erase: avoid collateral damage, fixes #6768
TW 3 年之前
父節點
當前提交
53b6d14cb4
共有 2 個文件被更改,包括 18 次插入8 次删除
  1. 16 6
      src/borg/helpers.py
  2. 2 2
      src/borg/repository.py

+ 16 - 6
src/borg/helpers.py

@@ -2389,13 +2389,23 @@ def json_print(obj):
     print(json_dump(obj))
 
 
-def secure_erase(path):
-    """Attempt to securely erase a file by writing random data over it before deleting it."""
+def secure_erase(path, *, avoid_collateral_damage):
+    """Attempt to securely erase a file by writing random data over it before deleting it.
+
+    If avoid_collateral_damage is True, we only secure erase if the total link count is 1,
+    otherwise we just do a normal "delete" (unlink) without first overwriting it with random.
+    This avoids other hardlinks pointing to same inode as <path> getting damaged, but might be less secure.
+    A typical scenario where this is useful are quick "hardlink copies" of bigger directories.
+
+    If avoid_collateral_damage is False, we always secure erase.
+    If there are hardlinks pointing to the same inode as <path>, they will contain random garbage afterwards.
+    """
     with open(path, 'r+b') as fd:
-        length = os.stat(fd.fileno()).st_size
-        fd.write(os.urandom(length))
-        fd.flush()
-        os.fsync(fd.fileno())
+        st = os.stat(fd.fileno())
+        if not (st.st_nlink > 1 and avoid_collateral_damage):
+            fd.write(os.urandom(st.st_size))
+            fd.flush()
+            os.fsync(fd.fileno())
     os.unlink(path)
 
 

+ 2 - 2
src/borg/repository.py

@@ -301,7 +301,7 @@ class Repository:
 
         if os.path.isfile(old_config_path):
             logger.warning("Old config file not securely erased on previous config update")
-            secure_erase(old_config_path)
+            secure_erase(old_config_path, avoid_collateral_damage=True)
 
         if os.path.isfile(config_path):
             link_error_msg = ("Failed to securely erase old repository config file (hardlinks not supported). "
@@ -328,7 +328,7 @@ class Repository:
                            "read-only repositories." % (e.strerror, e.filename))
 
         if os.path.isfile(old_config_path):
-            secure_erase(old_config_path)
+            secure_erase(old_config_path, avoid_collateral_damage=True)
 
     def save_key(self, keydata):
         assert self.config