Просмотр исходного кода

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 лет назад: 9
Родитель
Сommit
7c88ebf619
5 измененных файлов с 40 добавлено и 9 удалено
  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
     is already provided in .buildinfo files, and including it in the binary
     packages makes them unreproducible even when the profile used would not
     packages makes them unreproducible even when the profile used would not
     alter its contents. Closes: #831524
     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:
   * Portability:
     - On GNU/Hurd try to use the new process executable name attribute from
     - On GNU/Hurd try to use the new process executable name attribute from
       libps, to properly match on start-stop-daemon --exec.
       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;
     errno = 0;
     epoch = strtol(string, &eepochcolon, 10);
     epoch = strtol(string, &eepochcolon, 10);
+    if (string == eepochcolon)
+      return dpkg_put_error(err, _("epoch in version is empty"));
     if (colon != eepochcolon)
     if (colon != eepochcolon)
       return dpkg_put_error(err, _("epoch in version is not number"));
       return dpkg_put_error(err, _("epoch in version is not number"));
     if (epoch < 0)
     if (epoch < 0)
@@ -229,8 +231,12 @@ parseversion(struct dpkg_version *rversion, const char *string,
   }
   }
   rversion->version= nfstrnsave(string,end-string);
   rversion->version= nfstrnsave(string,end-string);
   hyphen= strrchr(rversion->version,'-');
   hyphen= strrchr(rversion->version,'-');
-  if (hyphen)
+  if (hyphen) {
     *hyphen++ = '\0';
     *hyphen++ = '\0';
+
+    if (*hyphen == '\0')
+      return dpkg_put_error(err, _("revision number is empty"));
+  }
   rversion->revision= hyphen ? hyphen : "";
   rversion->revision= hyphen ? hyphen : "";
 
 
   /* XXX: Would be faster to use something like cisversion and cisrevision. */
   /* 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(parseversion(&a, "0:0", NULL) == 0);
 	test_pass(dpkg_version_compare(&a, &b) == 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");
 	b = DPKG_VERSION_OBJECT(0, "0", "0");
 	test_pass(parseversion(&a, "0:0-0", NULL) == 0);
 	test_pass(parseversion(&a, "0:0-0", NULL) == 0);
 	test_pass(dpkg_version_compare(&a, &b) == 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_fail(parseversion(&a, "0:", &err) == 0);
 	test_error(err);
 	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 version with embedded spaces. */
 	test_fail(parseversion(&a, "0:0 0-1", &err) == 0);
 	test_fail(parseversion(&a, "0:0 0-1", &err) == 0);
 	test_error(err);
 	test_error(err);
@@ -293,7 +298,7 @@ test_version_parse(void)
 
 
 TEST_ENTRY(test)
 TEST_ENTRY(test)
 {
 {
-	test_plan(194);
+	test_plan(196);
 
 
 	test_version_blank();
 	test_version_blank();
 	test_version_is_informative();
 	test_version_is_informative();

+ 10 - 0
scripts/Dpkg/Version.pm

@@ -416,11 +416,21 @@ sub version_check($) {
         return (0, $msg) if wantarray;
         return (0, $msg) if wantarray;
         return 0;
         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()) {
     if (not defined $version->version() or not length $version->version()) {
         my $msg = g_('upstream version cannot be empty');
         my $msg = g_('upstream version cannot be empty');
         return (0, $msg) if wantarray;
         return (0, $msg) if wantarray;
         return 0;
         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]/) {
     if ($version->version() =~ m/^[^\d]/) {
         my $msg = g_('version number does not start with digit');
         my $msg = g_('version number does not start with digit');
         return (0, $msg) if wantarray;
         return (0, $msg) if wantarray;

+ 12 - 4
scripts/t/Dpkg_Version.t

@@ -30,7 +30,7 @@ my @ops = ('<', '<<', 'lt',
 	   '>=', 'ge',
 	   '>=', 'ge',
 	   '>', '>>', 'gt');
 	   '>', '>>', 'gt');
 
 
-plan tests => scalar(@tests) * (3 * scalar(@ops) + 4) + 24;
+plan tests => scalar(@tests) * (3 * scalar(@ops) + 4) + 30;
 
 
 sub dpkg_vercmp {
 sub dpkg_vercmp {
      my ($a, $cmp, $b) = @_;
      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 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->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');
 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');
 my $ver = Dpkg::Version->new('10a:5.2');
 ok(!$ver->is_valid(), 'bad epoch is invalid');
 ok(!$ver->is_valid(), 'bad epoch is invalid');
 ok(!$ver, 'bool eval of invalid leads to false');
 ok(!$ver, 'bool eval of invalid leads to false');
@@ -162,10 +170,10 @@ __DATA__
 1:0foo 0foo 1
 1:0foo 0foo 1
 0:0foo 0foo 0
 0:0foo 0foo 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 0fo 1
-0foo- 0foo+ -1
+0foo-0 0foo+ -1
 0foo~1 0foo -1
 0foo~1 0foo -1
 0foo~foo+Bar 0foo~foo+bar -1
 0foo~foo+Bar 0foo~foo+bar -1
 0foo~~ 0foo~ -1
 0foo~~ 0foo~ -1