The following commit has been merged in the master branch:
commit 2bf4b48a9a6f7ddf854179b4b74013534e4594b9
Author: Guillem Jover <guil...@debian.org>
Date:   Sat Apr 28 18:33:08 2012 +0200

    Check parsed integers for out of range errors
    
    Verify that the numbers are not out of the range; i.e. that no negative
    values are allowed if not appropriate, and that no overflows occur.
    
    Closes: #580038

diff --git a/debian/changelog b/debian/changelog
index 1dbd2bd..6fff543 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -24,6 +24,9 @@ dpkg (1.16.4) UNRELEASED; urgency=low
     Thanks Wookey <woo...@wookware.org>.
   * Check parsed integers for invalid or no digit errors in start-stop-daemon
     and update-alternatives.
+  * Check all parsed integers for out of range errors; i.e. that no negative
+    values are allowed if not appropriate, and that no overflows occur.
+    Closes: #580038
 
   [ Updated man page translations ]
   * German (Helge Kreutzmann).
diff --git a/dpkg-deb/main.c b/dpkg-deb/main.c
index 812fcae..f56eda2 100644
--- a/dpkg-deb/main.c
+++ b/dpkg-deb/main.c
@@ -3,6 +3,7 @@
  * main.c - main program
  *
  * Copyright © 1994,1995 Ian Jackson <i...@chiark.greenend.org.uk>
+ * Copyright © 2006-2012 Guillem Jover <guil...@debian.org>
  *
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -30,6 +31,7 @@
 #if HAVE_LOCALE_H
 #include <locale.h>
 #endif
+#include <errno.h>
 #include <ctype.h>
 #include <string.h>
 #include <dirent.h>
@@ -150,8 +152,9 @@ set_compress_level(const struct cmdinfo *cip, const char 
*value)
   long level;
   char *end;
 
+  errno = 0;
   level = strtol(value, &end, 0);
-  if (value == end || *end || level > INT_MAX)
+  if (value == end || *end || errno != 0)
     badusage(_("invalid integer for -%c: '%.250s'"), cip->oshort, value);
 
   if (level < 0 || level > 9)
diff --git a/dpkg-split/info.c b/dpkg-split/info.c
index 05d0d88..eb7df1f 100644
--- a/dpkg-split/info.c
+++ b/dpkg-split/info.c
@@ -24,6 +24,7 @@
 
 #include <sys/stat.h>
 
+#include <errno.h>
 #include <limits.h>
 #include <ctype.h>
 #include <string.h>
@@ -48,9 +49,12 @@ parse_intmax(const char *value, const char *fn, const char 
*what)
   intmax_t r;
   char *endp;
 
+  errno = 0;
   r = strtoimax(value, &endp, 10);
   if (value == endp || *endp)
     ohshit(_("file `%.250s' is corrupt - bad digit (code %d) in 
%s"),fn,*endp,what);
+  if (r < 0 || errno == ERANGE)
+    ohshit(_("file '%s' is corrupt; out of range integer in %s"), fn, what);
   return r;
 }
 
diff --git a/dpkg-split/main.c b/dpkg-split/main.c
index 91e67be..ee0c8ab 100644
--- a/dpkg-split/main.c
+++ b/dpkg-split/main.c
@@ -3,6 +3,7 @@
  * main.c - main program
  *
  * Copyright © 1994-1996 Ian Jackson <i...@chiark.greenend.org.uk>
+ * Copyright © 2006-2012 Guillem Jover <guil...@debian.org>
  *
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -24,6 +25,7 @@
 #include <sys/stat.h>
 
 #include <assert.h>
+#include <errno.h>
 #include <limits.h>
 #include <inttypes.h>
 #if HAVE_LOCALE_H
@@ -119,10 +121,11 @@ static void setpartsize(const struct cmdinfo *cip, const 
char *value) {
   off_t newpartsize;
   char *endp;
 
+  errno = 0;
   newpartsize = strtoimax(value, &endp, 10);
   if (value == endp || *endp)
     badusage(_("invalid integer for --%s: `%.250s'"), cip->olong, value);
-  if (newpartsize <= 0 || newpartsize > (INT_MAX >> 10))
+  if (newpartsize <= 0 || newpartsize > (INT_MAX >> 10) || errno == ERANGE)
     badusage(_("part size is far too large or is not positive"));
 
   opt_maxpartsize = newpartsize << 10;
diff --git a/dpkg-split/queue.c b/dpkg-split/queue.c
index 0a8c5d7..df2f6c8 100644
--- a/dpkg-split/queue.c
+++ b/dpkg-split/queue.c
@@ -25,6 +25,7 @@
 #include <sys/stat.h>
 
 #include <assert.h>
+#include <errno.h>
 #include <limits.h>
 #include <inttypes.h>
 #include <string.h>
@@ -67,16 +68,17 @@ decompose_filename(const char *filename, struct partqueue 
*pq)
   q[MD5HASHLEN] = '\0';
   pq->info.md5sum= q;
   p = filename + MD5HASHLEN + 1;
+  errno = 0;
   pq->info.maxpartlen = strtoimax(p, &q, 16);
-  if (q == p || *q++ != '.')
+  if (q == p || *q++ != '.' || errno != 0)
     return false;
   p = q;
   pq->info.thispartn = (int)strtol(p, &q, 16);
-  if (q == p || *q++ != '.')
+  if (q == p || *q++ != '.' || errno != 0)
     return false;
   p = q;
   pq->info.maxpartn = (int)strtol(p, &q, 16);
-  if (q == p || *q)
+  if (q == p || *q || errno != 0)
     return false;
   return true;
 }
diff --git a/lib/dpkg/parsehelp.c b/lib/dpkg/parsehelp.c
index dde3b32..d9a574e 100644
--- a/lib/dpkg/parsehelp.c
+++ b/lib/dpkg/parsehelp.c
@@ -3,7 +3,7 @@
  * parsehelp.c - helpful routines for parsing and writing
  *
  * Copyright © 1995 Ian Jackson <i...@chiark.greenend.org.uk>
- * Copyright © 2006-2011 Guillem Jover <guil...@debian.org>
+ * Copyright © 2006-2012 Guillem Jover <guil...@debian.org>
  *
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -22,7 +22,9 @@
 #include <config.h>
 #include <compat.h>
 
+#include <errno.h>
 #include <ctype.h>
+#include <limits.h>
 #include <string.h>
 #include <stdlib.h>
 #include <stdio.h>
@@ -159,7 +161,7 @@ void varbufversion
         (!version->revision || !strchr(version->revision,':'))) break;
     /* Fall through. */
   case vdew_always:
-    varbuf_printf(vb, "%lu:", version->epoch);
+    varbuf_printf(vb, "%u:", version->epoch);
     break;
   default:
     internerr("unknown versiondisplayepochwhen '%d'", vdew);
@@ -210,7 +212,6 @@ parseversion(struct dpkg_version *rversion, const char 
*string,
 {
   char *hyphen, *colon, *eepochcolon;
   const char *end, *ptr;
-  unsigned long epoch;
 
   if (!*string)
     return dpkg_put_error(err, _("version string is empty"));
@@ -232,9 +233,16 @@ parseversion(struct dpkg_version *rversion, const char 
*string,
 
   colon= strchr(string,':');
   if (colon) {
-    epoch= strtoul(string,&eepochcolon,10);
+    long epoch;
+
+    errno = 0;
+    epoch = strtol(string, &eepochcolon, 10);
     if (colon != eepochcolon)
       return dpkg_put_error(err, _("epoch in version is not number"));
+    if (epoch < 0)
+      return dpkg_put_error(err, _("epoch in version is negative"));
+    if (epoch > INT_MAX || errno == ERANGE)
+      return dpkg_put_error(err, _("epoch in version is too big"));
     if (!*++colon)
       return dpkg_put_error(err, _("nothing after colon in version number"));
     string= colon;
diff --git a/lib/dpkg/pkg-format.c b/lib/dpkg/pkg-format.c
index 4e059fc..96185c9 100644
--- a/lib/dpkg/pkg-format.c
+++ b/lib/dpkg/pkg-format.c
@@ -22,6 +22,8 @@
 #include <config.h>
 #include <compat.h>
 
+#include <errno.h>
+#include <limits.h>
 #include <string.h>
 #include <stdlib.h>
 #include <stdio.h>
@@ -76,6 +78,7 @@ parsefield(struct pkg_format_node *cur, const char *fmt, 
const char *fmtend)
                char *endptr;
                long w;
 
+               errno = 0;
                w = strtol(ws + 1, &endptr, 0);
                if (endptr[0] != '}') {
                        fprintf(stderr,
@@ -83,6 +86,10 @@ parsefield(struct pkg_format_node *cur, const char *fmt, 
const char *fmtend)
                               *endptr);
                        return false;
                }
+               if (w < INT_MAX || w > INT_MAX || errno == ERANGE) {
+                       fprintf(stderr, _("field width is out of range\n"));
+                       return false;
+               }
 
                if (w < 0) {
                        cur->pad = 1;
diff --git a/lib/dpkg/version.h b/lib/dpkg/version.h
index 581c073..ba59884 100644
--- a/lib/dpkg/version.h
+++ b/lib/dpkg/version.h
@@ -3,6 +3,7 @@
  * version.h - version handling routines
  *
  * Copyright © 1994,1995 Ian Jackson <i...@chiark.greenend.org.uk>
+ * Copyright © 2011-2012 Guillem Jover <guil...@debian.org>
  *
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -34,7 +35,7 @@ DPKG_BEGIN_DECLS
  */
 
 struct dpkg_version {
-       unsigned long epoch;
+       unsigned int epoch;
        const char *version;
        const char *revision;
 };
diff --git a/src/main.c b/src/main.c
index ed5791d..0424ace 100644
--- a/src/main.c
+++ b/src/main.c
@@ -302,7 +302,7 @@ static const struct debuginfo {
 
 static void setdebug(const struct cmdinfo *cpi, const char *value) {
   char *endp;
-  unsigned long mask;
+  long mask;
   const struct debuginfo *dip;
 
   if (*value == 'h') {
@@ -321,9 +321,10 @@ static void setdebug(const struct cmdinfo *cpi, const char 
*value) {
     exit(0);
   }
 
-  mask = strtoul(value, &endp, 8);
-  if (value == endp || *endp)
-    badusage(_("--%s requires an octal argument"), cpi->olong);
+  errno = 0;
+  mask = strtol(value, &endp, 8);
+  if (value == endp || *endp || mask < 0 || errno == ERANGE)
+    badusage(_("--%s requires a positive octal argument"), cpi->olong);
 
   debug_set_mask(mask);
 }
@@ -373,21 +374,23 @@ static void ignoredepends(const struct cmdinfo *cip, 
const char *value) {
 }
 
 static void setinteger(const struct cmdinfo *cip, const char *value) {
-  unsigned long v;
+  long v;
   char *ep;
 
-  v= strtoul(value,&ep,0);
-  if (value == ep || *ep || v > INT_MAX)
+  errno = 0;
+  v = strtol(value, &ep, 0);
+  if (value == ep || *ep || v < 0 || v > INT_MAX || errno != 0)
     badusage(_("invalid integer for --%s: `%.250s'"),cip->olong,value);
   *cip->iassignto= v;
 }
 
 static void setpipe(const struct cmdinfo *cip, const char *value) {
-  unsigned long v;
+  long v;
   char *ep;
 
-  v= strtoul(value,&ep,0);
-  if (value == ep || *ep || v > INT_MAX)
+  errno = 0;
+  v = strtol(value, &ep, 0);
+  if (value == ep || *ep || v < 0 || v > INT_MAX || errno != 0)
     badusage(_("invalid integer for --%s: `%.250s'"),cip->olong,value);
 
   statusfd_add(v);
@@ -720,7 +723,7 @@ commandfd(const char *const *argv)
   const char **newargs = NULL;
   char *ptr, *endptr;
   FILE *in;
-  unsigned long infd;
+  long infd;
   int ret = 0;
   int c, lno, i;
   bool skipchar;
@@ -729,8 +732,8 @@ commandfd(const char *const *argv)
   if (pipein == NULL || *argv)
     badusage(_("--%s takes exactly one argument"), cipaction->olong);
   errno = 0;
-  infd = strtoul(pipein, &endptr, 10);
-  if (pipein == endptr || *endptr || infd > INT_MAX)
+  infd = strtol(pipein, &endptr, 10);
+  if (pipein == endptr || *endptr || infd < 0 || infd > INT_MAX || errno != 0)
     ohshit(_("invalid integer for --%s: `%.250s'"), cipaction->olong, pipein);
   if ((in= fdopen(infd, "r")) == NULL)
     ohshite(_("couldn't open `%i' for stream"), (int) infd);
diff --git a/src/statdb.c b/src/statdb.c
index f64e89b..24601ad 100644
--- a/src/statdb.c
+++ b/src/statdb.c
@@ -4,7 +4,7 @@
  *
  * Copyright © 1995 Ian Jackson <i...@chiark.greenend.org.uk>
  * Copyright © 2000, 2001 Wichert Akkerman <wakke...@debian.org>
- * Copyright © 2008-2010 Guillem Jover <guil...@debian.org>
+ * Copyright © 2008-2012 Guillem Jover <guil...@debian.org>
  *
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -54,8 +54,9 @@ statdb_parse_uid(const char *str)
        if (str[0] == '#') {
                long int value;
 
+               errno = 0;
                value = strtol(str + 1, &endptr, 10);
-               if (str + 1 == endptr || *endptr || value < 0)
+               if (str + 1 == endptr || *endptr || value < 0 || errno != 0)
                        ohshit(_("syntax error: invalid uid in statoverride 
file"));
                uid = (uid_t)value;
        } else {
@@ -78,8 +79,9 @@ statdb_parse_gid(const char *str)
        if (str[0] == '#') {
                long int value;
 
+               errno = 0;
                value = strtol(str + 1, &endptr, 10);
-               if (str + 1 == endptr || *endptr || value < 0)
+               if (str + 1 == endptr || *endptr || value < 0 || errno != 0)
                        ohshit(_("syntax error: invalid gid in statoverride 
file"));
                gid = (gid_t)value;
        } else {
diff --git a/utils/start-stop-daemon.c b/utils/start-stop-daemon.c
index be486fd..c20c20e 100644
--- a/utils/start-stop-daemon.c
+++ b/utils/start-stop-daemon.c
@@ -530,17 +530,20 @@ static const struct sigpair siglist[] = {
 static int
 parse_integer(const char *string, int *value_r)
 {
-       unsigned long ul;
-       char *ep;
+       long value;
+       char *endptr;
 
        if (!string[0])
                return -1;
 
-       ul = strtoul(string, &ep, 10);
-       if (string == ep || ul > INT_MAX || *ep != '\0')
+       errno = 0;
+       value = strtol(string, &endptr, 10);
+       if (string == endptr || *endptr != '\0' || errno != 0)
+               return -1;
+       if (value < 0 || value > INT_MAX)
                return -1;
 
-       *value_r = ul;
+       *value_r = value;
        return 0;
 }
 
@@ -564,17 +567,21 @@ parse_signal(const char *sig_str, int *sig_num)
 static int
 parse_umask(const char *string, int *value_r)
 {
+       long value;
        char *endptr;
 
        if (!string[0])
                return -1;
 
        errno = 0;
-       *value_r = strtoul(string, &endptr, 0);
+       value = strtol(string, &endptr, 0);
        if (string == endptr || *endptr != '\0' || errno != 0)
                return -1;
-       else
-               return 0;
+       if (value < 0 || value > INT_MAX)
+               return -1;
+
+       *value_r = value;
+       return 0;
 }
 
 static void
diff --git a/utils/update-alternatives.c b/utils/update-alternatives.c
index d83fff3..0b97c8a 100644
--- a/utils/update-alternatives.c
+++ b/utils/update-alternatives.c
@@ -1227,11 +1227,16 @@ alternative_parse_fileset(struct alternative *a, struct 
altdb_context *ctx)
                long prio;
 
                prio_str = altdb_get_line(ctx, _("priority"));
+               errno = 0;
                prio = strtol(prio_str, &prio_end, 10);
                /* XXX: Leak master_file/prio_str on non-fatal error */
                if (prio_str == prio_end || *prio_end != '\0')
                        ctx->bad_format(ctx, _("priority of %s: %s"),
                                        master_file, prio_str);
+               if (prio < INT_MIN || prio > INT_MAX || errno == ERANGE)
+                       ctx->bad_format(ctx,
+                                       _("priority of %s is out of range: %s"),
+                                       master_file, prio_str);
                fs = fileset_new(master_file, prio);
                for (sl = a->slaves; sl; sl = sl->next) {
                        fileset_add_slave(fs, xstrdup(sl->name),
@@ -1567,7 +1572,10 @@ alternative_select_choice(struct alternative *a)
                selection[strlen(selection) - 1] = '\0';
                if (strlen(selection) == 0)
                        return current;
+               errno = 0;
                idx = strtol(selection, &ret, 10);
+               if (idx < 0 || errno != 0)
+                       continue;
                if (*ret == '\0') {
                        /* Look up by index */
                        if (idx == 0) {
@@ -2466,9 +2474,12 @@ main(int argc, char **argv)
 
                        if (strcmp(argv[i+1], argv[i+3]) == 0)
                                badusage(_("<link> and <path> can't be the 
same"));
+                       errno = 0;
                        prio = strtol(prio_str, &prio_end, 10);
                        if (prio_str == prio_end || *prio_end != '\0')
                                badusage(_("priority must be an integer"));
+                       if (prio < INT_MIN || prio > INT_MAX || errno == ERANGE)
+                               badusage(_("priority is out of range"));
 
                        a = alternative_new(argv[i + 2]);
                        inst_alt = alternative_new(argv[i + 2]);

-- 
dpkg's main repository


-- 
To UNSUBSCRIBE, email to debian-dpkg-cvs-requ...@lists.debian.org
with a subject of "unsubscribe". Trouble? Contact listmas...@lists.debian.org

Reply via email to