summaryrefslogtreecommitdiff
path: root/openbsd-compat
diff options
context:
space:
mode:
authorDamien Miller <djm@mindrot.org>2017-03-12 10:48:14 +1100
committerDamien Miller <djm@mindrot.org>2017-03-12 10:48:14 +1100
commitd94c1dfef2ea30ca67b1204ada7c3b537c54f4d0 (patch)
tree0a72ee991e2ac25cb9e176738671ccec3d89fa4c /openbsd-compat
parent894221a63fa061e52e414ca58d47edc5fe645968 (diff)
sync fmt_scaled.c with OpenBSD
revision 1.13 date: 2017/03/11 23:37:23; author: djm; state: Exp; lines: +14 -1; commitid: jnFKyHkB3CEiEZ2R; fix signed integer overflow in scan_scaled. Found by Nicolas Iooss using AFL against ssh_config. ok deraadt@ millert@ ---------------------------- revision 1.12 date: 2013/11/29 19:00:51; author: deraadt; state: Exp; lines: +6 -5; fairly simple unsigned char casts for ctype ok krw ---------------------------- revision 1.11 date: 2012/11/12 14:07:20; author: halex; state: Exp; lines: +4 -2; make scan_scaled set errno to EINVAL rather than ERANGE if it encounters an invalid multiplier, like the man page says it should "looks sensible" deraadt@, ok ian@ ---------------------------- revision 1.10 date: 2009/06/20 15:00:04; author: martynas; state: Exp; lines: +4 -4; use llabs instead of the home-grown version; and some comment changes ok ian@, millert@ ----------------------------
Diffstat (limited to 'openbsd-compat')
-rw-r--r--openbsd-compat/fmt_scaled.c34
1 files changed, 25 insertions, 9 deletions
diff --git a/openbsd-compat/fmt_scaled.c b/openbsd-compat/fmt_scaled.c
index edd682a49..e5533b2de 100644
--- a/openbsd-compat/fmt_scaled.c
+++ b/openbsd-compat/fmt_scaled.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: fmt_scaled.c,v 1.9 2007/03/20 03:42:52 tedu Exp $ */ 1/* $OpenBSD: fmt_scaled.c,v 1.13 2017/03/11 23:37:23 djm Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 2001, 2002, 2003 Ian F. Darwin. All rights reserved. 4 * Copyright (c) 2001, 2002, 2003 Ian F. Darwin. All rights reserved.
@@ -69,7 +69,7 @@ static long long scale_factors[] = {
69 69
70#define MAX_DIGITS (SCALE_LENGTH * 3) /* XXX strlen(sprintf("%lld", -1)? */ 70#define MAX_DIGITS (SCALE_LENGTH * 3) /* XXX strlen(sprintf("%lld", -1)? */
71 71
72/** Convert the given input string "scaled" into numeric in "result". 72/* Convert the given input string "scaled" into numeric in "result".
73 * Return 0 on success, -1 and errno set on error. 73 * Return 0 on success, -1 and errno set on error.
74 */ 74 */
75int 75int
@@ -81,7 +81,7 @@ scan_scaled(char *scaled, long long *result)
81 long long scale_fact = 1, whole = 0, fpart = 0; 81 long long scale_fact = 1, whole = 0, fpart = 0;
82 82
83 /* Skip leading whitespace */ 83 /* Skip leading whitespace */
84 while (isascii(*p) && isspace(*p)) 84 while (isascii((unsigned char)*p) && isspace((unsigned char)*p))
85 ++p; 85 ++p;
86 86
87 /* Then at most one leading + or - */ 87 /* Then at most one leading + or - */
@@ -108,7 +108,8 @@ scan_scaled(char *scaled, long long *result)
108 * (but note that E for Exa might look like e to some!). 108 * (but note that E for Exa might look like e to some!).
109 * Advance 'p' to end, to get scale factor. 109 * Advance 'p' to end, to get scale factor.
110 */ 110 */
111 for (; isascii(*p) && (isdigit(*p) || *p=='.'); ++p) { 111 for (; isascii((unsigned char)*p) &&
112 (isdigit((unsigned char)*p) || *p=='.'); ++p) {
112 if (*p == '.') { 113 if (*p == '.') {
113 if (fract_digits > 0) { /* oops, more than one '.' */ 114 if (fract_digits > 0) { /* oops, more than one '.' */
114 errno = EINVAL; 115 errno = EINVAL;
@@ -124,6 +125,10 @@ scan_scaled(char *scaled, long long *result)
124 /* ignore extra fractional digits */ 125 /* ignore extra fractional digits */
125 continue; 126 continue;
126 fract_digits++; /* for later scaling */ 127 fract_digits++; /* for later scaling */
128 if (fpart >= LLONG_MAX / 10) {
129 errno = ERANGE;
130 return -1;
131 }
127 fpart *= 10; 132 fpart *= 10;
128 fpart += i; 133 fpart += i;
129 } else { /* normal digit */ 134 } else { /* normal digit */
@@ -131,6 +136,10 @@ scan_scaled(char *scaled, long long *result)
131 errno = ERANGE; 136 errno = ERANGE;
132 return -1; 137 return -1;
133 } 138 }
139 if (whole >= LLONG_MAX / 10) {
140 errno = ERANGE;
141 return -1;
142 }
134 whole *= 10; 143 whole *= 10;
135 whole += i; 144 whole += i;
136 } 145 }
@@ -150,17 +159,22 @@ scan_scaled(char *scaled, long long *result)
150 /* Validate scale factor, and scale whole and fraction by it. */ 159 /* Validate scale factor, and scale whole and fraction by it. */
151 for (i = 0; i < SCALE_LENGTH; i++) { 160 for (i = 0; i < SCALE_LENGTH; i++) {
152 161
153 /** Are we there yet? */ 162 /* Are we there yet? */
154 if (*p == scale_chars[i] || 163 if (*p == scale_chars[i] ||
155 *p == tolower(scale_chars[i])) { 164 *p == tolower((unsigned char)scale_chars[i])) {
156 165
157 /* If it ends with alphanumerics after the scale char, bad. */ 166 /* If it ends with alphanumerics after the scale char, bad. */
158 if (isalnum(*(p+1))) { 167 if (isalnum((unsigned char)*(p+1))) {
159 errno = EINVAL; 168 errno = EINVAL;
160 return -1; 169 return -1;
161 } 170 }
162 scale_fact = scale_factors[i]; 171 scale_fact = scale_factors[i];
163 172
173 if (whole >= LLONG_MAX / scale_fact) {
174 errno = ERANGE;
175 return -1;
176 }
177
164 /* scale whole part */ 178 /* scale whole part */
165 whole *= scale_fact; 179 whole *= scale_fact;
166 180
@@ -181,7 +195,9 @@ scan_scaled(char *scaled, long long *result)
181 return 0; 195 return 0;
182 } 196 }
183 } 197 }
184 errno = ERANGE; 198
199 /* Invalid unit or character */
200 errno = EINVAL;
185 return -1; 201 return -1;
186} 202}
187 203
@@ -196,7 +212,7 @@ fmt_scaled(long long number, char *result)
196 unsigned int i; 212 unsigned int i;
197 unit_type unit = NONE; 213 unit_type unit = NONE;
198 214
199 abval = (number < 0LL) ? -number : number; /* no long long_abs yet */ 215 abval = llabs(number);
200 216
201 /* Not every negative long long has a positive representation. 217 /* Not every negative long long has a positive representation.
202 * Also check for numbers that are just too darned big to format 218 * Also check for numbers that are just too darned big to format