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