Browse Source

libdpkg, Dpkg::Version: Do not allow empty epochs and revisions

When there's at least one colon or one dash, we should expect epoch
and revision numbers.
Guillem Jover 7 years ago
parent
commit
7c88ebf619
5 changed files with 40 additions and 9 deletions
  1. 2 0
      debian/changelog
  2. 7 1
      lib/dpkg/parsehelp.c
  3. 9 4
      lib/dpkg/t/t-version.c
  4. 10 0
      scripts/Dpkg/Version.pm
  5. 12 4
      scripts/t/Dpkg_Version.t

+ 2 - 0
debian/changelog

@@ -5,6 +5,8 @@ dpkg (1.18.19) UNRELEASED; urgency=medium
     is already provided in .buildinfo files, and including it in the binary
     packages makes them unreproducible even when the profile used would not
     alter its contents. Closes: #831524
+  * Do not allow empty epochs and revisions in versions. When there's at
+    least one colon or one dash, we should expect epoch and revision numbers.
   * Portability:
     - On GNU/Hurd try to use the new process executable name attribute from
       libps, to properly match on start-stop-daemon --exec.

+ 7 - 1
lib/dpkg/parsehelp.c

@@ -214,6 +214,8 @@ parseversion(struct dpkg_version *rversion, const char *string,
 
     errno = 0;
     epoch = strtol(string, &eepochcolon, 10);
+    if (string == eepochcolon)
+      return dpkg_put_error(err, _("epoch in version is empty"));
     if (colon != eepochcolon)
       return dpkg_put_error(err, _("epoch in version is not number"));
     if (epoch < 0)
@@ -229,8 +231,12 @@ parseversion(struct dpkg_version *rversion, const char *string,
   }
   rversion->version= nfstrnsave(string,end-string);
   hyphen= strrchr(rversion->version,'-');
-  if (hyphen)
+  if (hyphen) {
     *hyphen++ = '\0';
+
+    if (*hyphen == '\0')
+      return dpkg_put_error(err, _("revision number is empty"));
+  }
   rversion->revision= hyphen ? hyphen : "";
 
   /* XXX: Would be faster to use something like cisversion and cisrevision. */

+ 9 - 4
lib/dpkg/t/t-version.c

@@ -163,9 +163,6 @@ test_version_parse(void)
 	test_pass(parseversion(&a, "0:0", NULL) == 0);
 	test_pass(dpkg_version_compare(&a, &b) == 0);
 
-	test_pass(parseversion(&a, "0:0-", NULL) == 0);
-	test_pass(dpkg_version_compare(&a, &b) == 0);
-
 	b = DPKG_VERSION_OBJECT(0, "0", "0");
 	test_pass(parseversion(&a, "0:0-0", NULL) == 0);
 	test_pass(dpkg_version_compare(&a, &b) == 0);
@@ -239,6 +236,14 @@ test_version_parse(void)
 	test_fail(parseversion(&a, "0:", &err) == 0);
 	test_error(err);
 
+	/* Test empty epoch in version. */
+	test_fail(parseversion(&a, ":1.0", &err) == 0);
+	test_error(err);
+
+	/* Test empty revision in version. */
+	test_fail(parseversion(&a, "1.0-", &err) == 0);
+	test_error(err);
+
 	/* Test version with embedded spaces. */
 	test_fail(parseversion(&a, "0:0 0-1", &err) == 0);
 	test_error(err);
@@ -293,7 +298,7 @@ test_version_parse(void)
 
 TEST_ENTRY(test)
 {
-	test_plan(194);
+	test_plan(196);
 
 	test_version_blank();
 	test_version_is_informative();

+ 10 - 0
scripts/Dpkg/Version.pm

@@ -416,11 +416,21 @@ sub version_check($) {
         return (0, $msg) if wantarray;
         return 0;
     }
+    if (not defined $version->epoch() or not length $version->epoch()) {
+        my $msg = sprintf(g_('epoch part of the version number cannot be empty'));
+        return (0, $msg) if wantarray;
+        return 0;
+    }
     if (not defined $version->version() or not length $version->version()) {
         my $msg = g_('upstream version cannot be empty');
         return (0, $msg) if wantarray;
         return 0;
     }
+    if (not defined $version->revision() or not length $version->revision()) {
+        my $msg = sprintf(g_('revision cannot be empty'));
+        return (0, $msg) if wantarray;
+        return 0;
+    }
     if ($version->version() =~ m/^[^\d]/) {
         my $msg = g_('version number does not start with digit');
         return (0, $msg) if wantarray;

+ 12 - 4
scripts/t/Dpkg_Version.t

@@ -30,7 +30,7 @@ my @ops = ('<', '<<', 'lt',
 	   '>=', 'ge',
 	   '>', '>>', 'gt');
 
-plan tests => scalar(@tests) * (3 * scalar(@ops) + 4) + 24;
+plan tests => scalar(@tests) * (3 * scalar(@ops) + 4) + 30;
 
 sub dpkg_vercmp {
      my ($a, $cmp, $b) = @_;
@@ -96,6 +96,14 @@ $empty = Dpkg::Version->new('0:-0');
 ok($empty eq '0:-0', "Dpkg::Version->new('0:-0') eq '0:-0'");
 ok($empty->as_string() eq '0:-0', "Dpkg::Version->new('0:-0')->as_string() eq '0:-0'");
 ok(!$empty->is_valid(), 'empty upstream version with epoch is invalid');
+$empty = Dpkg::Version->new(':1.0');
+ok($empty eq ':1.0', "Dpkg::Version->new(':1.0') eq ':1.0'");
+ok($empty->as_string() eq ':1.0', "Dpkg::Version->new(':1.0')->as_string() eq ':1.0'");
+ok(!$empty->is_valid(), 'empty epoch is invalid');
+$empty = Dpkg::Version->new('1.0-');
+ok($empty eq '1.0-', "Dpkg::Version->new('1.0-') eq '1.0-'");
+ok($empty->as_string() eq '1.0-', "Dpkg::Version->new('1.0-')->as_string() eq '1.0-'");
+ok(!$empty->is_valid(), 'empty revision is invalid');
 my $ver = Dpkg::Version->new('10a:5.2');
 ok(!$ver->is_valid(), 'bad epoch is invalid');
 ok(!$ver, 'bool eval of invalid leads to false');
@@ -162,10 +170,10 @@ __DATA__
 1:0foo 0foo 1
 0:0foo 0foo 0
 0foo 0foo 0
-0foo- 0foo 0
-0foo- 0foo-0 0
+0foo-0 0foo 0
+0foo 0foo-0 0
 0foo 0fo 1
-0foo- 0foo+ -1
+0foo-0 0foo+ -1
 0foo~1 0foo -1
 0foo~foo+Bar 0foo~foo+bar -1
 0foo~~ 0foo~ -1