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:
parent
23f6a82f1b
commit
2117861738
2 changed files with 29 additions and 0 deletions
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue