diff options
author | Guillem Jover <guillem@debian.org> | 2017-08-20 10:03:33 +0200 |
---|---|---|
committer | Guillem Jover <guillem@debian.org> | 2017-08-26 10:59:37 +0200 |
commit | 59f63342b9121b9d941d3dbd09487c953a113f6e (patch) | |
tree | e15c43a79d09736f0d45c0e1f51e7b68799d0fd5 | |
parent | 99b3e1c276af88327b5f9423cfdf75afead28018 (diff) | |
download | dpkg-59f63342b9121b9d941d3dbd09487c953a113f6e.tar.gz |
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
-rw-r--r-- | debian/changelog | 2 | ||||
-rw-r--r-- | lib/dpkg/deb-version.c | 27 | ||||
-rw-r--r-- | lib/dpkg/t/t-deb-version.c | 22 |
3 files changed, 44 insertions, 7 deletions
diff --git a/debian/changelog b/debian/changelog index c78831926..9278737b7 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@thykier.net>. Closes: #846405 * Always use the binary version for the .buildinfo filename in dpkg-genbuildinfo. Reported by Raphaƫl Hertzog <hertzog@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 ea53a592a..cee5ddd6a 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 2e069073c..fef115142 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(); } |