Merge lp:~dawgfoto/duplicity/fixup1252 into lp:~duplicity-team/duplicity/0.8-series

Proposed by Martin Nowak
Status: Merged
Merged at revision: 1302
Proposed branch: lp:~dawgfoto/duplicity/fixup1252
Merge into: lp:~duplicity-team/duplicity/0.8-series
Diff against target: 49 lines (+7/-6)
2 files modified
bin/duplicity (+5/-4)
duplicity/collections.py (+2/-2)
To merge this branch: bzr merge lp:~dawgfoto/duplicity/fixup1252
Reviewer Review Type Date Requested Status
duplicity-team Pending
Review via email: mp+343816@code.launchpad.net

Commit message

* only check decryptable remote manifests
  - fixup of revision 1252 which introduces a non-fatal error message (see #1729796)
  - for backups the GPG private key and/or it's password are typically not available
  - also avoid interactive password queries through e.g. gpg agent

To post a comment you must log in.
Revision history for this message
edso (ed.so) wrote :

hey Martin,

while the patch looks sound, i'd really like to know why the manifest is retrieved/decrypted from backend in the first place, before it get's applied.

@Ken?

..ede/duply.net

Revision history for this message
Martin Nowak (dawgfoto) wrote :

Seems like it tries to catch corruptions see https://bazaar.launchpad.net/~duplicity-team/duplicity/0.8-series/view/1301/bin/duplicity#L1333 and https://bazaar.launchpad.net/~duplicity-team/duplicity/0.8-series/view/1301/duplicity/collections.py#L218.
Given that this is not possible with an encrypted backup (without the key and/or password) and that the check hasn't been done despite the "non-fatal" error message, it seems fine to me to just skip it.

lp:~dawgfoto/duplicity/fixup1252 updated
1303. By Martin Nowak

* only check decryptable remote manifests
  - fixup of revision 1252 which introduces a non-fatal error message (see #1729796)
  - for backups the GPG private key and/or it's password are typically not available
  - also avoid interactive password queries through e.g. gpg agent

Revision history for this message
Martin Nowak (dawgfoto) wrote :

Changed the patch to still check the local manifest.

Revision history for this message
edso (ed.so) wrote :

hey Martin,

are you aware of the "no private key issue/double key approach" as eg. described here
  https://lists.gnu.org/archive/html/duplicity-talk/2017-10/msg00015.html
?

On 23.04.2018 15:50, Martin Nowak wrote:
> Seems like it tries to catch corruptions see https://bazaar.launchpad.net/~duplicity-team/duplicity/0.8-series/view/1301/bin/duplicity#L1333 and https://bazaar.launchpad.net/~duplicity-team/duplicity/0.8-series/view/1301/duplicity/collections.py#L218.

ok, isee the manifests are compared, which sounds reasonable.

> Given that this is not possible with an encrypted backup (without the key and/or password)

it is ;) when a private key and passphrase (might be empty) for one of the used public keys is available.
as i don't see a way to easily detect a private key available (duply has some shell gpg trickery for this though) i don't see a problem logging the gpg error as a warning and simply continue.

>
and that the check hasn't been done despite the "non-fatal" error message, it seems fine to me to just skip it.
>

i'd rather log a warning that the comparison was skipped because of the decryption impossibility, so the user may be informed that a /surplus/ security measure was not applied.

finally: the current mode of allowing incrementals w/o validating the backend is error prone[1] and should be replaced in a future version of duplicity. but as it stands, nobody took care of it until today.

food for thought ..ede/duply.net

[1] https://bugs.launchpad.net/duplicity/+bug/687295

Revision history for this message
Martin Nowak (dawgfoto) wrote :

What's the corruption scenario that manifest comparison should protect against?

The manifest contains volume checksums, but those aren't checked against the volumes.
Eventually the remote manifest is just a copy of the local one. Multiple duplicity instances writing to the same remote should be ruled out as well.

The only thing that seems possible is an incomplete backup, but FWIW duplicitly only renames a local temp manifest and uploads it to the remote once the full backup is done.

Revision history for this message
edso (ed.so) wrote :

On 24.04.2018 18:20, Martin Nowak wrote:
> What's the corruption scenario that manifest comparison should protect against?
>
> The manifest contains volume checksums, but those aren't checked against the volumes.

they should, at least during verify/restore

> Eventually the remote manifest is just a copy of the local one. Multiple duplicity instances writing to the same remote should be ruled out as well.

you never know. better safe than sorry.

>
> The only thing that seems possible is an incomplete backup, but FWIW duplicitly only renames a local temp manifest and uploads it to the remote once the full backup is done.
>

or some corruption in the backend or local file system or..

what stays is the question how a corrupt manifest would affect an incremental or resumed backup?
@Ken: do you want to chime in, as this smells like your area of expertise?

additionally of course, the question still remains if this check makes sense there at all. obviously someone at some point thought so in the past, but no harm in revalidating.

..ede/duply.net

Revision history for this message
Kenneth Loafman (kenneth-loafman) wrote :

The manifest check was in the original code I inherited. It's the only
file verified physically against the remote, the rest are hash based. That
verification has not caused many problems, and to my knowledge, has
detected very few comparison errors, so maybe it should just go away now.

As to hash checking on the remote, it's really not possible with the dumb
remotes we use. We only use list/del/read/write. Kinda minimal by design.

To answer @ede's question: The corruption would most likely be a
truncation, not a bit flip. As such, we would not have the hashes of the
diffdir volumes to compare against. I've never tried to run an incremental
or a restore with the check disabled and a known corrupted manifest. Could
be interesting to try.

On Wed, Apr 25, 2018 at 8:51 AM, edso <email address hidden> wrote:

> On 24.04.2018 18:20, Martin Nowak wrote:
> > What's the corruption scenario that manifest comparison should protect
> against?
> >
> > The manifest contains volume checksums, but those aren't checked against
> the volumes.
>
> they should, at least during verify/restore
>
> > Eventually the remote manifest is just a copy of the local one. Multiple
> duplicity instances writing to the same remote should be ruled out as well.
>
> you never know. better safe than sorry.
>
> >
> > The only thing that seems possible is an incomplete backup, but FWIW
> duplicitly only renames a local temp manifest and uploads it to the remote
> once the full backup is done.
> >
>
> or some corruption in the backend or local file system or..
>
> what stays is the question how a corrupt manifest would affect an
> incremental or resumed backup?
> @Ken: do you want to chime in, as this smells like your area of
> expertise?
>
> additionally of course, the question still remains if this check makes
> sense there at all. obviously someone at some point thought so in the past,
> but no harm in revalidating.
>
> ..ede/duply.net
>
> --
> https://code.launchpad.net/~dawgfoto/duplicity/fixup1252/+merge/343816
> You are subscribed to branch lp:duplicity.
>

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'bin/duplicity'
2--- bin/duplicity 2017-12-21 21:35:52 +0000
3+++ bin/duplicity 2018-04-23 13:59:40 +0000
4@@ -1327,10 +1327,11 @@
5 @rtype: void
6 @return: void
7 """
8- if not col_stats.all_backup_chains:
9- return
10+ assert col_stats.all_backup_chains
11 last_backup_set = col_stats.all_backup_chains[-1].get_last()
12- last_backup_set.check_manifests()
13+ # check remote manifest only if we can decrypt it (see #1729796)
14+ check_remote = not globals.encryption or globals.gpg_profile.passphrase
15+ last_backup_set.check_manifests(check_remote=check_remote)
16
17
18 def check_resources(action):
19@@ -1630,7 +1631,7 @@
20 # only ask for a passphrase if there was a previous backup
21 if col_stats.all_backup_chains:
22 globals.gpg_profile.passphrase = get_passphrase(1, action)
23- check_last_manifest(col_stats) # not needed for full backup
24+ check_last_manifest(col_stats) # not needed for full backups
25 incremental_backup(sig_chain)
26 globals.backend.close()
27 log.shutdown()
28
29=== modified file 'duplicity/collections.py'
30--- duplicity/collections.py 2018-01-20 02:07:53 +0000
31+++ duplicity/collections.py 2018-04-23 13:59:40 +0000
32@@ -202,7 +202,7 @@
33 """
34 return dup_time.timetopretty(self.time or self.end_time)
35
36- def check_manifests(self):
37+ def check_manifests(self, check_remote=True):
38 """
39 Make sure remote manifest is equal to local one
40 """
41@@ -211,7 +211,7 @@
42 log.ErrorCode.no_manifests)
43 assert self.remote_manifest_name, "if only one, should be remote"
44
45- remote_manifest = self.get_remote_manifest()
46+ remote_manifest = self.get_remote_manifest() if check_remote else None
47 if self.local_manifest_path:
48 local_manifest = self.get_local_manifest()
49 if remote_manifest and self.local_manifest_path and local_manifest:

Subscribers

People subscribed via source and target branches