From: Ian Jackson Date: Sun, 31 May 2015 11:15:45 +0000 (+0100) Subject: New approach to replay prevention - WIP X-Git-Tag: debian/0.30~130 X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=dgit.git;a=commitdiff_plain;h=fb73b55ade7687b65727b1146b860ea892425cc6 New approach to replay prevention - WIP --- diff --git a/dgit b/dgit index 42f9f457..759df20e 100755 --- a/dgit +++ b/dgit @@ -1650,9 +1650,9 @@ sub dopush ($) { if ($forceflag && defined $lastpush_hash) { git_for_each_tag_referring($lastpush_hash, sub { - my ($objid,$refobjid,$fullrefname,$tagname) = @_; - responder_send_command("supersedes $fullrefname=$objid"); - $supersedes{$fullrefname} = $objid; + my ($tagobjid,$refobjid,$fullrefname,$tagname) = @_; + responder_send_command("supersedes $fullrefname=$tagobjid"); + $supersedes{$fullrefname} = $tagobjid; }); } diff --git a/infra/dgit-repos-server b/infra/dgit-repos-server index e794de25..ab831364 100755 --- a/infra/dgit-repos-server +++ b/infra/dgit-repos-server @@ -632,10 +632,10 @@ sub checksuite () { } sub checktagnoreplay () { - # We check that the signed tag mentions the name and value of + # We check that the signed tag mentions the name and tag object id of # (a) in the case of FRESHREPO all tags in the repo; # (b) in the case of just NOFFCHECK all tags referring to - # the current head for the suite (there must be at least one). + # the current head for the suite (there must be at least one). # This prevents a replay attack using an earlier signed tag. return unless $policy & (FRESHREPO|NOFFCHECK); @@ -677,14 +677,29 @@ sub checktagnoreplay () { my @problems; git_for_each_tag_referring($onlyreferring, sub { - my ($objid,$refobjid,$fullrefname,$tagname) = @_; - printdebug "checktagnoreplay - overwriting $fullrefname=$objid\n"; + my ($tagobjid,$refobjid,$fullrefname,$tagname) = @_; + printdebug "checktagnoreplay - overwriting". + " $fullrefname=$tagobjid->$refobjid\n"; my $supers = $supersedes{$fullrefname}; if (!defined $supers) { - push @problems, "does not supersede $fullrefname"; - } elsif ($supers ne $objid) { + printdebug "checktagnoreply - fallbacks\n"; + my $super_fallback = 0; + foreach my $didsuper (sort keys %supersedes) { + my $didsuper_tagobjid = $supersedes{$didsuper}; + my $didsuper_refobjid = git_rev_parse $didsuper_tagobjid; + printdebug "checktagnoreply - fallback". + " $didsuper=$didsuper_refobjid->$didsuper_tagobjid\n"; + last if + $refobjid ne $didsuper_refobjid + and is_fast_fwd($refobjid, $didsuper_refobjid); + printdebug "checktagnoreply - fallback $didsuper OK\n"; + $super_fallback = 1; + } + push @problems, "does not supersede $fullrefname" + unless $super_fallback; + } elsif ($supers ne $tagobjid) { push @problems, - "supersedes $fullrefname=$supers but previously $fullrefname=$objid"; + "supersedes $fullrefname=$supers but previously $fullrefname=$tagobjid"; } else { # ok; }