Forráskód Böngészése

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
Guillem Jover 14 éve
szülő
commit
2bf4b48a9a

+ 3 - 0
debian/changelog

@@ -24,6 +24,9 @@ dpkg (1.16.4) UNRELEASED; urgency=low
     Thanks Wookey <wookey@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).

+ 4 - 1
dpkg-deb/main.c

@@ -3,6 +3,7 @@
  * main.c - main program
  *
  * Copyright © 1994,1995 Ian Jackson <ian@chiark.greenend.org.uk>
+ * Copyright © 2006-2012 Guillem Jover <guillem@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)

+ 4 - 0
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;
 }
 

+ 4 - 1
dpkg-split/main.c

@@ -3,6 +3,7 @@
  * main.c - main program
  *
  * Copyright © 1994-1996 Ian Jackson <ian@chiark.greenend.org.uk>
+ * Copyright © 2006-2012 Guillem Jover <guillem@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;

+ 5 - 3
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;
 }

+ 12 - 4
lib/dpkg/parsehelp.c

@@ -3,7 +3,7 @@
  * parsehelp.c - helpful routines for parsing and writing
  *
  * Copyright © 1995 Ian Jackson <ian@chiark.greenend.org.uk>
- * Copyright © 2006-2011 Guillem Jover <guillem@debian.org>
+ * Copyright © 2006-2012 Guillem Jover <guillem@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;

+ 7 - 0
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;

+ 2 - 1
lib/dpkg/version.h

@@ -3,6 +3,7 @@
  * version.h - version handling routines
  *
  * Copyright © 1994,1995 Ian Jackson <ian@chiark.greenend.org.uk>
+ * Copyright © 2011-2012 Guillem Jover <guillem@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;
 };

+ 16 - 13
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);

+ 5 - 3
src/statdb.c

@@ -4,7 +4,7 @@
  *
  * Copyright © 1995 Ian Jackson <ian@chiark.greenend.org.uk>
  * Copyright © 2000, 2001 Wichert Akkerman <wakkerma@debian.org>
- * Copyright © 2008-2010 Guillem Jover <guillem@debian.org>
+ * Copyright © 2008-2012 Guillem Jover <guillem@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 {

+ 15 - 8
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

+ 11 - 0
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]);