chiark / gitweb /
dgit: fix rpush+buildinfo: Transfer buildinfos for signing.
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Sat, 8 Jul 2017 16:22:53 +0000 (17:22 +0100)
committerIan Jackson <ijackson@chiark.greenend.org.uk>
Sat, 8 Jul 2017 16:23:02 +0000 (17:23 +0100)
buildinfos are supposed to be signed.  And, indeed, if they are
present, debsign wants to sign them.  That means they need to be
transferred to the signing end, and back again.

We check that the filename is not totally unreasonable, but do not
attempt to verify it completely.  If there are situations where
unwanted or confusing buildinfos are generated, this is the fault of
the build process.  dgit rpush should, in this respect, do the same as
debsign+dput - ie faithfully sign and upload what the build has
provided.

We do check that the buildinfo doesn't look too much like a .changes,
and mentions the same files as the .changes (insofar as they mention
files in common).  This is a rather nugatory defence against some
kinds of bait and switch attacks.

This is in some sense an incompatible protocol change: if the build
host has a new dgit, and sends buildinfos, an old dgit on the
initiator will declare a protocol violation.  However, the new
protocol elements occur only when needed.  in this situation, the only
way to get things to work at all with the old dgit at either end would
be to strip out the buildinfos, which is obviously undesirable.

Closes:#867693.

Signed-off-by: Ian Jackson <ijackson@chiark.greenend.org.uk>
debian/changelog
dgit

index 73a0035..942c77b 100644 (file)
@@ -1,6 +1,7 @@
 dgit (3.11~) unstable; urgency=medium
 
-  * 
+  * dgit: fix rpush+buildinfo: Transfer buildinfos for signing.
+    Closes:#867693.
 
  --
 
diff --git a/dgit b/dgit
index c2622ef..6134f5c 100755 (executable)
--- a/dgit
+++ b/dgit
@@ -316,6 +316,9 @@ sub gbp_pq {
 #  > param tagformat old|new
 #  > param maint-view MAINT-VIEW-HEAD
 #
+#  > param buildinfo-filename P_V_X.buildinfo   # zero or more times
+#  > file buildinfo                             # for buildinfos to sign
+#
 #  > previously REFNAME=OBJNAME       # if --deliberately-not-fast-forward
 #                                     # goes into tag, for replay prevention
 #
@@ -332,6 +335,9 @@ sub gbp_pq {
 #  [etc]
 #  < data-block NBYTES    [transfer of signed changes]
 #  [etc]
+#  < data-block NBYTES    [transfer of each signed buildinfo
+#  [etc]                   same number and order as "file buildinfo"]
+#  ...
 #  < files-end
 #
 #  > complete
@@ -4296,6 +4302,14 @@ END
        responder_send_command("param maint-view $maintviewhead");
     }
 
+    # Perhaps send buildinfo(s) for signing
+    my $changes_files = getfield $changes, 'Files';
+    my @buildinfos = ($changes_files =~ m/ .* (\S+\.buildinfo)$/mg);
+    foreach my $bi (@buildinfos) {
+       responder_send_command("param buildinfo-filename $bi");
+       responder_send_file('buildinfo', "$buildproductsdir/$bi");
+    }
+
     if (deliberately_not_fast_forward) {
        git_for_each_ref(lrfetchrefs, sub {
            my ($objid,$objtype,$lrfetchrefname,$reftail) = @_;
@@ -4367,6 +4381,7 @@ END
     if ($we_are_responder) {
        my $dryrunsuffix = act_local() ? "" : ".tmp";
        my @rfiles = ($dscpath, $changesfile);
+       push @rfiles, map { "$buildproductsdir/$_" } @buildinfos;
        responder_receive_files('signed-dsc-changes',
                                map { "$_$dryrunsuffix" } @rfiles);
     } else {
@@ -4719,7 +4734,7 @@ sub i_resp_want ($) {
     print RI "files-end\n" or die $!;
 }
 
-our ($i_clogp, $i_version, $i_dscfn, $i_changesfn);
+our ($i_clogp, $i_version, $i_dscfn, $i_changesfn, @i_buildinfos);
 
 sub i_localname_parsed_changelog {
     return "remote-changelog.822";
@@ -4736,6 +4751,31 @@ sub i_localname_dsc {
 }
 sub i_file_dsc { }
 
+sub i_localname_buildinfo ($) {
+    my $bi = $i_param{'buildinfo-filename'};
+    defined $bi or badproto \*RO, "buildinfo before filename";
+    defined $i_changesfn or badproto \*RO, "buildinfo before changes";
+    $bi =~ m{^\Q$package\E_[!-.0-~]*\.buildinfo$}s
+       or badproto \*RO, "improper buildinfo filename";
+    return $&;
+}
+sub i_file_buildinfo {
+    my $bi = $i_param{'buildinfo-filename'};
+    my $bd = parsecontrol "$i_tmp/$bi", $bi;
+    my $ch = parsecontrol "$i_tmp/$i_changesfn", 'changes';
+    if (!forceing [qw(buildinfo-changes-mismatch)]) {
+       files_compare_inputs($bd, $ch);
+       (getfield $bd, $_) eq (getfield $ch, $_) or
+           fail "buildinfo mismatch $_"
+           foreach qw(Source Version);
+       !defined $bd->{$_} or
+           fail "buildinfo contains $_"
+           foreach qw(Changes Changed-by Distribution);
+    }
+    push @i_buildinfos, $bi;
+    delete $i_param{'buildinfo-filename'};
+}
+
 sub i_localname_changes {
     defined $i_dscfn or badproto \*RO, "dsc (before parsed-changelog)";
     $i_changesfn = $i_dscfn;
@@ -4777,7 +4817,7 @@ sub i_want_signed_tag {
 sub i_want_signed_dsc_changes {
     rename "$i_dscfn.tmp","$i_dscfn" or die "$i_dscfn $!";
     sign_changes $i_changesfn;
-    return ($i_dscfn, $i_changesfn);
+    return ($i_dscfn, $i_changesfn, @i_buildinfos);
 }
 
 #---------- building etc. ----------