diff options
author | Lars Wirzenius <liw@liw.fi> | 2015-06-13 09:35:40 +0300 |
---|---|---|
committer | Lars Wirzenius <liw@liw.fi> | 2015-06-13 09:35:40 +0300 |
commit | c20af9c9ca8f562a5c51a6f4c333cbceb55369b7 (patch) | |
tree | cd0c4b81b2914197a87ad1f6ddf6cb8f3349b767 | |
parent | bfce4f638fcf9986c527d493e412021fd448e624 (diff) | |
download | obnam-c20af9c9ca8f562a5c51a6f4c333cbceb55369b7.tar.gz |
Prevent restores to a non-empty --to directory
-rw-r--r-- | NEWS | 4 | ||||
-rw-r--r-- | debian/changelog | 8 | ||||
-rw-r--r-- | obnamlib/plugins/restore_plugin.py | 13 | ||||
-rw-r--r-- | yarns/0030-basics.yarn | 25 |
4 files changed, 49 insertions, 1 deletions
@@ -38,6 +38,10 @@ Minor fixes: text. This is now done in `python setup.py docs` instead. The latter is an optional build step, and probably only works on Debian. +* `obnam restore --to=DIR` now requires that the directory `DIR` + either doesn't exist, or it is empty when the restore starts. This + is to prevent users from restore on top of a running system. + Version 1.9, released 2015-03-22 -------------------------------- diff --git a/debian/changelog b/debian/changelog index 7bbc8abb..7f59d522 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,11 @@ +obnam (1.10-1) UNRELEASED; urgency=medium + + * New upstream version. + * Fix "restore to /tmp messes up directory perms" by preventing + restores to a non-empty directory. (Closes: #760492) + + -- Lars Wirzenius <liw@liw.fi> Sat, 13 Jun 2015 09:34:51 +0300 + obnam (1.9-1) unstable; urgency=low * Update debian/copyright years. Thanks to Jan Niggemann. diff --git a/obnamlib/plugins/restore_plugin.py b/obnamlib/plugins/restore_plugin.py index 88ea15b7..677d8200 100644 --- a/obnamlib/plugins/restore_plugin.py +++ b/obnamlib/plugins/restore_plugin.py @@ -37,6 +37,11 @@ class RestoreErrors(obnamlib.ObnamError): ''' +class RestoreTargetNotEmpty(obnamlib.ObnamError): + + msg = '''The restore --to directory ({to}) is not empty.''' + + class Hardlinks(object): '''Keep track of inodes with unrestored hardlinks.''' @@ -82,7 +87,8 @@ class RestorePlugin(obnamlib.ObnamPlugin): arg_synopsis='[DIRECTORY]...') self.app.settings.string( ['to'], - 'where to restore or FUSE mount') + 'where to restore or FUSE mount; ' + 'for restores, must be empty or must not exist') self.app.settings.string_list( ['generation'], 'which generation to restore', @@ -138,6 +144,11 @@ class RestorePlugin(obnamlib.ObnamPlugin): self.fs = self.app.fsf.new(self.app.settings['to'], create=True) self.fs.connect() + # The --to directory MUST be empty, to prevent users from + # accidentally restoring over /. + if self.fs.listdir('.') != []: + raise RestoreTargetNotEmpty(to=self.app.settings['to']) + # Set permissions on this directory to be quite # restrictive, so that nobody else can access the files # while the restore is happening. The directory named by diff --git a/yarns/0030-basics.yarn b/yarns/0030-basics.yarn index 4bc8439b..631177a3 100644 --- a/yarns/0030-basics.yarn +++ b/yarns/0030-basics.yarn @@ -200,6 +200,31 @@ the manifest to avoid getting an error. AND user U restores file L/F to X from their latest generation in repository R THEN L/F, restored to X, matches manifest M +Restores must happen to a non-existent or an empty directory +------------------------------------------------------------ + +To avoid people doing unfortunate things such as `obnam restore +--to=/` we make sure the target directory of restore either does not +exist, or it's empty. + + SCENARIO restore only to empty or new target + GIVEN 1kB of new data in directory L + AND a manifest of L in M + AND 0kB of new data in directory EMPTY + AND 2kB of new data in directory NOTEMPTY + + WHEN user U backs up directory L to repository R + AND user U restores their latest generation in repository R into EMPTY + THEN L, restored to EMPTY, matches manifest M + + WHEN user U restores their latest generation in repository R into NOTEXIST + THEN L, restored to NOTEXIST, matches manifest M + + WHEN user U attempts to restore their latest generation + ... in repository R into NOTEMPTY + THEN the attempt failed with exit code 1 + + Pretend backing up: the `--pretend` setting ------------------------------------------- |