Add structured exception for known Automake vulnerabilities
authorJacob Bachmeyer <jcb@gnu.org>
Thu, 3 Nov 2022 22:37:07 +0000 (17:37 -0500)
committerJacob Bachmeyer <jcb@gnu.org>
Thu, 3 Nov 2022 22:37:07 +0000 (17:37 -0500)
gatekeeper.pl
testsuite/lib/gatekeeper.exp

index 84ccd6048cbb1bc45fc91983c8b2c76171af2967..d6676f66a7dc9cb21b4977f0456ba482267e5a86 100755 (executable)
@@ -581,6 +581,34 @@ END
     { return join("\n", map join(': ', @$_), @{(shift)->{trace}})."\n" }
 }
 
+{
+  package Local::Exception::known_vulnerability;
+  {our @ISA = qw(Local::Exception)}
+
+  sub summary { return 'upload found vulnerable to '
+                 .join(', ', sort keys %{(shift)->{issues}}) }
+
+  sub message {
+    my $self = shift;
+
+    my $text = "file rejected because:\n";
+
+    # Because CVE-2012-3386 was not fixed until 1.11.6 / 1.12.2, we point
+    # people to that version instead of 1.11.1, which fixes
+    # CVE-2009-4029. Ward, 2012-07-20
+    $text .= <<"END" if $self->{issues}{'CVE-2009-4029'};
+$self->{file} contains a vulnerable Makefile.in (CVE-2009-4029).
+  Regenerate it with automake 1.11.6 / 1.12.2 or newer.
+END
+    $text .= <<"END" if $self->{issues}{'CVE-2012-3386'};
+$self->{file} contains a vulnerable Makefile.in (CVE-2012-3386).
+  Regenerate it with automake 1.11.6 / 1.12.2 or newer.
+END
+
+    return $text
+  }
+}
+
 {
   package Local::Exception::signature_from_future;
   {our @ISA = qw(Local::Exception)}
@@ -2134,15 +2162,21 @@ sub check_replay {
   }
 }
 
+=item automake_tests ( $upload_file )
+
+Examine UPLOAD_FILE for known vulnerabilities that certain (now ancient)
+versions of GNU Automake can introduce.  Returns nothing, but throws an
+exception if UPLOAD_FILE is found to be exploitable.
+
+=cut
+
 sub automake_tests {
   my $upload_file = shift;
 
-  my $error_string = '';
-
-  return "Error: $upload_file not found\n\n"
+  die "file not found: $upload_file"
     unless -e $upload_file;
 
-  return "Error: $upload_file is unreadable\n\n"
+  die "file not readable: $upload_file"
     unless -r $upload_file;
 
   # Reject an upload tarball if it contains a Makefile.in vulnerable
@@ -2157,58 +2191,52 @@ sub automake_tests {
       if DEBUG;
     my @tar_cmd = (qw(/bin/tar -tf), $upload_file);
     open TAR, '-|', @tar_cmd
-      or return 'Error: failed to run command: '.join(' ',@tar_cmd)."\n\n";
+      or die 'failed to run command: '.join(' ',@tar_cmd).": $!";
     my $found_makefile = 0;
     while (<TAR>) { $found_makefile++, last if m/Makefile.in/i }
     close TAR; # We don't care about errors here; the pipe can cause
                # non-zero exit codes when tar is unhappy that it's asked
                # to stop
-    return '' unless $found_makefile;
+    return unless $found_makefile;
 
     # If it does, check inside them
-    my $found_cve_2009_4029 = 0;
-    my $found_cve_2012_3386 = 0;
+    my %issues = ();
     ftp_syslog('debug',"DEBUG: found Makefile.in, "
         ."testing for CVE-2009-4029 and CVE-2012-3386")
       if DEBUG;
     @tar_cmd = (qw(/bin/tar --to-stdout -x -f), $upload_file,
                qw(Makefile.in --wildcards */Makefile.in));
     open TAR, '-|', @tar_cmd
-      or return 'Error: failed to run command: '.join(' ',@tar_cmd)."\n\n";
+      or die 'failed to run command: '.join(' ',@tar_cmd).": $!";
     while (<TAR>) {
-      $found_cve_2009_4029 = 1
+      $issues{'CVE-2009-4029'} = 1
        if m/perm -777 -exec chmod a\+rwx|chmod 777 \$\(distdir\)/;
-      $found_cve_2012_3386 = 1
+      $issues{'CVE-2012-3386'} = 1
        if m/chmod a\+w \$\(distdir\)/;
     }
     close TAR; # We don't care about errors here; the pipe can cause
                # non-zero exit codes when tar is unhappy that it's asked
                # to stop
 
-    # Because CVE-2012-3386 was not fixed until 1.11.6 / 1.12.2, we point
-    # people to that version instead of 1.11.1, which fixes
-    # CVE-2009-4029. Ward, 2012-07-20
-    $error_string .= "file rejected: $upload_file contains a vulnerable "
-      . "Makefile.in (CVE-2009-4029);\n"
-       . "Regenerate it with automake 1.11.6 / 1.12.2 or newer.\n\n"
-         if $found_cve_2009_4029;
+    throw known_vulnerability => file => $upload_file, issues => \%issues
+      if %issues;
+  }
+}
 
-    $error_string .= "file rejected: $upload_file contains a vulnerable "
-      . "Makefile.in (CVE-2012-3386);\n"
-       . "Regenerate it with automake 1.11.6 / 1.12.2 or newer.\n\n"
-         if $found_cve_2012_3386;
+=item check_vulnerabilities ( $upload_file )
 
-  }
+Examine UPLOAD_FILE for known vulnerabilities.  This is only used for
+issues related to packaging; notably an old issue in GNU Automake.
 
-  return $error_string;
-}
+Returns nothing on success and throws an exception if a known vulnerability
+is found in UPLOAD_FILE.
+
+=cut
 
 sub check_vulnerabilities {
   my $upload_file = shift;
 
-  my $error_string = automake_tests($upload_file);
-
-  return $error_string;
+  automake_tests($upload_file);
 }
 
 \f
@@ -2263,9 +2291,7 @@ sub check_files {
   fatal("gpg verify of upload file ($header->{filename}) failed",1)
     unless $valid;
 
-  my $error_string = check_vulnerabilities($upload_file);
-
-  fatal($error_string,1,'',3) if ($error_string ne '');
+  check_vulnerabilities($upload_file);
 
   ftp_syslog('debug', "DEBUG: "
             ."tested negative for CVE-2009-4029 and CVE-2012-3386") if DEBUG;
index ed8c9554357f36d2ea0040109122cff76d9854ca..7eefcac6185d649f5194c3a072b80c999ad04da6 100644 (file)
@@ -822,7 +822,7 @@ proc analyze_log { base_dir name assess } {
                     exp_continue
                 }
        -re {^gatekeeper\[[0-9]+\]: \(Test\) \[EX\]\
-                file rejected: [^()]+\((CVE-[0-9-]+)\)[^\r\n]+} {
+                upload found vulnerable to (CVE-[0-9-]+)[^\r\n]*} {
                     # from check_vulnerabilities via check_files
                     set A(exploit-check-fail,$expect_out(1,string)) 1
                     exp_continue