diff --git a/src/borg/helpers.py b/src/borg/helpers.py index dc4d34852..9c112d116 100644 --- a/src/borg/helpers.py +++ b/src/borg/helpers.py @@ -2256,3 +2256,13 @@ def json_dump(obj): 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.""" + 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()) + os.unlink(path) diff --git a/src/borg/repository.py b/src/borg/repository.py index 41d865d54..d7b84ab38 100644 --- a/src/borg/repository.py +++ b/src/borg/repository.py @@ -18,6 +18,7 @@ from .helpers import Location from .helpers import ProgressIndicatorPercent from .helpers import bin_to_hex from .helpers import yes +from .helpers import secure_erase from .locking import Lock, LockError, LockErrorT from .logger import create_logger from .lrucache import LRUCache @@ -182,9 +183,27 @@ class Repository: def save_config(self, path, config): config_path = os.path.join(path, 'config') + old_config_path = os.path.join(path, 'config.old') + + if os.path.isfile(old_config_path): + logger.warning("Old config file not securely erased on previous config update") + secure_erase(old_config_path) + + if os.path.isfile(config_path): + try: + os.link(config_path, old_config_path) + except OSError as e: + if e.errno in (errno.EMLINK, errno.EPERM): + logger.warning("Hardlink failed, cannot securely erase old config file") + else: + raise + with SaveFile(config_path) as fd: config.write(fd) + if os.path.isfile(old_config_path): + secure_erase(old_config_path) + def save_key(self, keydata): assert self.config keydata = keydata.decode('utf-8') # remote repo: msgpack issue #99, getting bytes