[dpkg] 86/192: libdpkg: Fix integer overflow in deb(5) version parser

Ximin Luo infinity0 at debian.org
Tue Oct 17 11:04:03 UTC 2017


This is an automated email from the git hooks/post-receive script.

infinity0 pushed a commit to branch pu/reproducible_builds
in repository dpkg.

commit 59f63342b9121b9d941d3dbd09487c953a113f6e
Author: Guillem Jover <guillem at debian.org>
Date:   Sun Aug 20 10:03:33 2017 +0200

    libdpkg: Fix integer overflow in deb(5) version parser
    
    The previous code was both not checking for overflows, and triggering
    undefined behavior as it was overflowing a signed integer.
    
    Closes: #868356
---
 debian/changelog           |  2 ++
 lib/dpkg/deb-version.c     | 27 +++++++++++++++++++++------
 lib/dpkg/t/t-deb-version.c | 22 +++++++++++++++++++++-
 3 files changed, 44 insertions(+), 7 deletions(-)

diff --git a/debian/changelog b/debian/changelog
index c788319..9278737 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -9,6 +9,8 @@ dpkg (1.19.0) UNRELEASED; urgency=medium
     Based on a patch by Niels Thykier <niels at thykier.net>. Closes: #846405
   * Always use the binary version for the .buildinfo filename in
     dpkg-genbuildinfo. Reported by Raphaël Hertzog <hertzog at debian.org>.
+  * Fix integer overflow in deb(5) format version parser.
+    Closes: #868356
   * Perl modules:
     - Switch from Dpkg::Util to List::Util, now that the module in the
       new required Perl contains the needed functions.
diff --git a/lib/dpkg/deb-version.c b/lib/dpkg/deb-version.c
index ea53a59..cee5ddd 100644
--- a/lib/dpkg/deb-version.c
+++ b/lib/dpkg/deb-version.c
@@ -21,6 +21,7 @@
 #include <config.h>
 #include <compat.h>
 
+#include <limits.h>
 #include <string.h>
 #include <stdlib.h>
 
@@ -46,19 +47,33 @@ const char *
 deb_version_parse(struct deb_version *version, const char *str)
 {
 	const char *str_minor, *end;
-	int major = 0;
-	int minor = 0;
+	unsigned int major = 0;
+	unsigned int minor = 0;
+	unsigned int divlimit = INT_MAX / 10;
+	int modlimit = INT_MAX % 10;
 
-	for (end = str; *end && c_isdigit(*end); end++)
-		major = major * 10  + *end - '0';
+	for (end = str; *end && c_isdigit(*end); end++) {
+		int ord = *end - '0';
+
+		if (major > divlimit || (major == divlimit && ord > modlimit))
+			return _("format version with too big major component");
+
+		major = major * 10  + ord;
+	}
 
 	if (end == str)
 		return _("format version with empty major component");
 	if (*end != '.')
 		return _("format version has no dot");
 
-	for (end = str_minor = end + 1; *end && c_isdigit(*end); end++)
-		minor = minor * 10 + *end - '0';
+	for (end = str_minor = end + 1; *end && c_isdigit(*end); end++) {
+		int ord = *end - '0';
+
+		if (minor > divlimit || (minor == divlimit && ord > modlimit))
+			return _("format version with too big minor component");
+
+		minor = minor * 10 + ord;
+	}
 
 	if (end == str_minor)
 		return _("format version with empty minor component");
diff --git a/lib/dpkg/t/t-deb-version.c b/lib/dpkg/t/t-deb-version.c
index 2e06907..fef1151 100644
--- a/lib/dpkg/t/t-deb-version.c
+++ b/lib/dpkg/t/t-deb-version.c
@@ -21,6 +21,9 @@
 #include <config.h>
 #include <compat.h>
 
+#include <limits.h>
+#include <stdio.h>
+
 #include <dpkg/test.h>
 #include <dpkg/deb-version.h>
 
@@ -28,6 +31,7 @@ static void
 test_deb_version_parse(void)
 {
 	struct deb_version v;
+	char *vs;
 
 	/* Test valid versions. */
 	test_pass(deb_version_parse(&v, "0.0") == NULL);
@@ -59,12 +63,28 @@ test_deb_version_parse(void)
 	test_fail(deb_version_parse(&v, "4.4 ") == NULL);
 	test_fail(deb_version_parse(&v, " 5.5 ") == NULL);
 
+	/* Test integer limits. */
+	if (asprintf(&vs, "%d.0", INT_MAX) < 0)
+		test_bail("cannot allocate memory for asprintf()");
+	test_pass(deb_version_parse(&v, vs) == NULL);
+	free(vs);
+
+	if (asprintf(&vs, "%d.0", INT_MAX - 1) < 0)
+		test_bail("cannot allocate memory for asprintf()");
+	test_pass(deb_version_parse(&v, vs) == NULL);
+	free(vs);
+
+	if (asprintf(&vs, "%ld.0", (long int)(1L + INT_MAX)) < 0)
+		test_bail("cannot allocate memory for asprintf()");
+	test_fail(deb_version_parse(&v, vs) == NULL);
+	free(vs);
+
 	/* FIXME: Complete. */
 }
 
 TEST_ENTRY(test)
 {
-	test_plan(21);
+	test_plan(24);
 
 	test_deb_version_parse();
 }

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/reproducible/dpkg.git



More information about the Reproducible-commits mailing list