1
0
Fork 0
mirror of https://github.com/borgbackup/borg.git synced 2024-12-25 01:06:50 +00:00

Securely erase config file, fixes #2257

The SaveFile code, while ensuring atomicity, did not allow for secure
erasure of the config file (containing the old encrypted key). Now it
creates a hardlink to the file, lets SaveFile do its thing, and writes
random data over the old file (via the hardlink). A secure erase is
needed because the config file can contain the old key after changing
one's password.
This commit is contained in:
Milkey Mouse 2017-03-08 22:38:37 -08:00 committed by enkore
parent 23f6a82f1b
commit 2117861738
2 changed files with 29 additions and 0 deletions

View file

@ -2256,3 +2256,13 @@ def json_dump(obj):
def json_print(obj): def json_print(obj):
print(json_dump(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)

View file

@ -18,6 +18,7 @@
from .helpers import ProgressIndicatorPercent from .helpers import ProgressIndicatorPercent
from .helpers import bin_to_hex from .helpers import bin_to_hex
from .helpers import yes from .helpers import yes
from .helpers import secure_erase
from .locking import Lock, LockError, LockErrorT from .locking import Lock, LockError, LockErrorT
from .logger import create_logger from .logger import create_logger
from .lrucache import LRUCache from .lrucache import LRUCache
@ -182,9 +183,27 @@ def create(self, path):
def save_config(self, path, config): def save_config(self, path, config):
config_path = os.path.join(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: with SaveFile(config_path) as fd:
config.write(fd) config.write(fd)
if os.path.isfile(old_config_path):
secure_erase(old_config_path)
def save_key(self, keydata): def save_key(self, keydata):
assert self.config assert self.config
keydata = keydata.decode('utf-8') # remote repo: msgpack issue #99, getting bytes keydata = keydata.decode('utf-8') # remote repo: msgpack issue #99, getting bytes