musl: backport various post-1.1.15 fixes
[openwrt/staging/wigyori.git] / toolchain / musl / patches / 040-fix-integer-overflows-and-uncaught-eoverflow-in-printf-core.patch
1 From 167dfe9672c116b315e72e57a55c7769f180dffa Mon Sep 17 00:00:00 2001
2 From: Rich Felker <dalias@aerifal.cx>
3 Date: Thu, 20 Oct 2016 00:22:09 -0400
4 Subject: fix integer overflows and uncaught EOVERFLOW in printf core
5
6 this patch fixes a large number of missed internal signed-overflow
7 checks and errors in determining when the return value (output length)
8 would exceed INT_MAX, which should result in EOVERFLOW. some of the
9 issues fixed were reported by Alexander Cherepanov; others were found
10 in subsequent review of the code.
11
12 aside from the signed overflows being undefined behavior, the
13 following specific bugs were found to exist in practice:
14
15 - overflows computing length of floating point formats with huge
16 explicit precisions, integer formats with prefix characters and huge
17 explicit precisions, or string arguments or format strings longer
18 than INT_MAX, resulted in wrong return value and wrong %n results.
19
20 - literal width and precision values outside the range of int were
21 misinterpreted, yielding wrong behavior in at least one well-defined
22 case: string formats with precision greater than INT_MAX were
23 sometimes truncated.
24
25 - in cases where EOVERFLOW is produced, incorrect values could be
26 written for %n specifiers past the point of exceeding INT_MAX.
27
28 in addition to fixing these bugs, we now stop producing output
29 immediately when output length would exceed INT_MAX, rather than
30 continuing and returning an error only at the end.
31 ---
32 src/stdio/vfprintf.c | 72 +++++++++++++++++++++++++++++++++++----------------
33 src/stdio/vfwprintf.c | 63 +++++++++++++++++++++++++++-----------------
34 2 files changed, 89 insertions(+), 46 deletions(-)
35
36 diff --git a/src/stdio/vfprintf.c b/src/stdio/vfprintf.c
37 index cd17ad7..e2ab2dc 100644
38 --- a/src/stdio/vfprintf.c
39 +++ b/src/stdio/vfprintf.c
40 @@ -272,6 +272,8 @@ static int fmt_fp(FILE *f, long double y, int w, int p, int fl, int t)
41 if (s-buf==1 && (y||p>0||(fl&ALT_FORM))) *s++='.';
42 } while (y);
43
44 + if (p > INT_MAX-2-(ebuf-estr)-pl)
45 + return -1;
46 if (p && s-buf-2 < p)
47 l = (p+2) + (ebuf-estr);
48 else
49 @@ -383,17 +385,22 @@ static int fmt_fp(FILE *f, long double y, int w, int p, int fl, int t)
50 p = MIN(p,MAX(0,9*(z-r-1)+e-j));
51 }
52 }
53 + if (p > INT_MAX-1-(p || (fl&ALT_FORM)))
54 + return -1;
55 l = 1 + p + (p || (fl&ALT_FORM));
56 if ((t|32)=='f') {
57 + if (e > INT_MAX-l) return -1;
58 if (e>0) l+=e;
59 } else {
60 estr=fmt_u(e<0 ? -e : e, ebuf);
61 while(ebuf-estr<2) *--estr='0';
62 *--estr = (e<0 ? '-' : '+');
63 *--estr = t;
64 + if (ebuf-estr > INT_MAX-l) return -1;
65 l += ebuf-estr;
66 }
67
68 + if (l > INT_MAX-pl) return -1;
69 pad(f, ' ', w, pl+l, fl);
70 out(f, prefix, pl);
71 pad(f, '0', w, pl+l, fl^ZERO_PAD);
72 @@ -437,8 +444,10 @@ static int fmt_fp(FILE *f, long double y, int w, int p, int fl, int t)
73
74 static int getint(char **s) {
75 int i;
76 - for (i=0; isdigit(**s); (*s)++)
77 - i = 10*i + (**s-'0');
78 + for (i=0; isdigit(**s); (*s)++) {
79 + if (i > INT_MAX/10U || **s-'0' > INT_MAX-10*i) i = -1;
80 + else i = 10*i + (**s-'0');
81 + }
82 return i;
83 }
84
85 @@ -446,12 +455,12 @@ static int printf_core(FILE *f, const char *fmt, va_list *ap, union arg *nl_arg,
86 {
87 char *a, *z, *s=(char *)fmt;
88 unsigned l10n=0, fl;
89 - int w, p;
90 + int w, p, xp;
91 union arg arg;
92 int argpos;
93 unsigned st, ps;
94 int cnt=0, l=0;
95 - int i;
96 + size_t i;
97 char buf[sizeof(uintmax_t)*3+3+LDBL_MANT_DIG/4];
98 const char *prefix;
99 int t, pl;
100 @@ -459,18 +468,19 @@ static int printf_core(FILE *f, const char *fmt, va_list *ap, union arg *nl_arg,
101 char mb[4];
102
103 for (;;) {
104 + /* This error is only specified for snprintf, but since it's
105 + * unspecified for other forms, do the same. Stop immediately
106 + * on overflow; otherwise %n could produce wrong results. */
107 + if (l > INT_MAX - cnt) goto overflow;
108 +
109 /* Update output count, end loop when fmt is exhausted */
110 - if (cnt >= 0) {
111 - if (l > INT_MAX - cnt) {
112 - errno = EOVERFLOW;
113 - cnt = -1;
114 - } else cnt += l;
115 - }
116 + cnt += l;
117 if (!*s) break;
118
119 /* Handle literal text and %% format specifiers */
120 for (a=s; *s && *s!='%'; s++);
121 for (z=s; s[0]=='%' && s[1]=='%'; z++, s+=2);
122 + if (z-a > INT_MAX-cnt) goto overflow;
123 l = z-a;
124 if (f) out(f, a, l);
125 if (l) continue;
126 @@ -498,9 +508,9 @@ static int printf_core(FILE *f, const char *fmt, va_list *ap, union arg *nl_arg,
127 } else if (!l10n) {
128 w = f ? va_arg(*ap, int) : 0;
129 s++;
130 - } else return -1;
131 + } else goto inval;
132 if (w<0) fl|=LEFT_ADJ, w=-w;
133 - } else if ((w=getint(&s))<0) return -1;
134 + } else if ((w=getint(&s))<0) goto overflow;
135
136 /* Read precision */
137 if (*s=='.' && s[1]=='*') {
138 @@ -511,24 +521,29 @@ static int printf_core(FILE *f, const char *fmt, va_list *ap, union arg *nl_arg,
139 } else if (!l10n) {
140 p = f ? va_arg(*ap, int) : 0;
141 s+=2;
142 - } else return -1;
143 + } else goto inval;
144 + xp = (p>=0);
145 } else if (*s=='.') {
146 s++;
147 p = getint(&s);
148 - } else p = -1;
149 + xp = 1;
150 + } else {
151 + p = -1;
152 + xp = 0;
153 + }
154
155 /* Format specifier state machine */
156 st=0;
157 do {
158 - if (OOB(*s)) return -1;
159 + if (OOB(*s)) goto inval;
160 ps=st;
161 st=states[st]S(*s++);
162 } while (st-1<STOP);
163 - if (!st) return -1;
164 + if (!st) goto inval;
165
166 /* Check validity of argument type (nl/normal) */
167 if (st==NOARG) {
168 - if (argpos>=0) return -1;
169 + if (argpos>=0) goto inval;
170 } else {
171 if (argpos>=0) nl_type[argpos]=st, arg=nl_arg[argpos];
172 else if (f) pop_arg(&arg, st, ap);
173 @@ -584,6 +599,7 @@ static int printf_core(FILE *f, const char *fmt, va_list *ap, union arg *nl_arg,
174 case 'u':
175 a = fmt_u(arg.i, z);
176 }
177 + if (xp && p<0) goto overflow;
178 if (p>=0) fl &= ~ZERO_PAD;
179 if (!arg.i && !p) {
180 a=z;
181 @@ -599,9 +615,9 @@ static int printf_core(FILE *f, const char *fmt, va_list *ap, union arg *nl_arg,
182 if (1) a = strerror(errno); else
183 case 's':
184 a = arg.p ? arg.p : "(null)";
185 - z = memchr(a, 0, p);
186 - if (!z) z=a+p;
187 - else p=z-a;
188 + z = a + strnlen(a, p<0 ? INT_MAX : p);
189 + if (p<0 && *z) goto overflow;
190 + p = z-a;
191 fl &= ~ZERO_PAD;
192 break;
193 case 'C':
194 @@ -611,8 +627,9 @@ static int printf_core(FILE *f, const char *fmt, va_list *ap, union arg *nl_arg,
195 p = -1;
196 case 'S':
197 ws = arg.p;
198 - for (i=l=0; i<0U+p && *ws && (l=wctomb(mb, *ws++))>=0 && l<=0U+p-i; i+=l);
199 + for (i=l=0; i<p && *ws && (l=wctomb(mb, *ws++))>=0 && l<=p-i; i+=l);
200 if (l<0) return -1;
201 + if (i > INT_MAX) goto overflow;
202 p = i;
203 pad(f, ' ', w, p, fl);
204 ws = arg.p;
205 @@ -623,12 +640,16 @@ static int printf_core(FILE *f, const char *fmt, va_list *ap, union arg *nl_arg,
206 continue;
207 case 'e': case 'f': case 'g': case 'a':
208 case 'E': case 'F': case 'G': case 'A':
209 + if (xp && p<0) goto overflow;
210 l = fmt_fp(f, arg.f, w, p, fl, t);
211 + if (l<0) goto overflow;
212 continue;
213 }
214
215 if (p < z-a) p = z-a;
216 + if (p > INT_MAX-pl) goto overflow;
217 if (w < pl+p) w = pl+p;
218 + if (w > INT_MAX-cnt) goto overflow;
219
220 pad(f, ' ', w, pl+p, fl);
221 out(f, prefix, pl);
222 @@ -646,8 +667,15 @@ static int printf_core(FILE *f, const char *fmt, va_list *ap, union arg *nl_arg,
223 for (i=1; i<=NL_ARGMAX && nl_type[i]; i++)
224 pop_arg(nl_arg+i, nl_type[i], ap);
225 for (; i<=NL_ARGMAX && !nl_type[i]; i++);
226 - if (i<=NL_ARGMAX) return -1;
227 + if (i<=NL_ARGMAX) goto inval;
228 return 1;
229 +
230 +inval:
231 + errno = EINVAL;
232 + return -1;
233 +overflow:
234 + errno = EOVERFLOW;
235 + return -1;
236 }
237
238 int vfprintf(FILE *restrict f, const char *restrict fmt, va_list ap)
239 diff --git a/src/stdio/vfwprintf.c b/src/stdio/vfwprintf.c
240 index f9f1ecf..b8fff20 100644
241 --- a/src/stdio/vfwprintf.c
242 +++ b/src/stdio/vfwprintf.c
243 @@ -154,8 +154,10 @@ static void out(FILE *f, const wchar_t *s, size_t l)
244
245 static int getint(wchar_t **s) {
246 int i;
247 - for (i=0; iswdigit(**s); (*s)++)
248 - i = 10*i + (**s-'0');
249 + for (i=0; iswdigit(**s); (*s)++) {
250 + if (i > INT_MAX/10U || **s-'0' > INT_MAX-10*i) i = -1;
251 + else i = 10*i + (**s-'0');
252 + }
253 return i;
254 }
255
256 @@ -168,8 +170,8 @@ static const char sizeprefix['y'-'a'] = {
257 static int wprintf_core(FILE *f, const wchar_t *fmt, va_list *ap, union arg *nl_arg, int *nl_type)
258 {
259 wchar_t *a, *z, *s=(wchar_t *)fmt;
260 - unsigned l10n=0, litpct, fl;
261 - int w, p;
262 + unsigned l10n=0, fl;
263 + int w, p, xp;
264 union arg arg;
265 int argpos;
266 unsigned st, ps;
267 @@ -181,20 +183,19 @@ static int wprintf_core(FILE *f, const wchar_t *fmt, va_list *ap, union arg *nl_
268 wchar_t wc;
269
270 for (;;) {
271 + /* This error is only specified for snprintf, but since it's
272 + * unspecified for other forms, do the same. Stop immediately
273 + * on overflow; otherwise %n could produce wrong results. */
274 + if (l > INT_MAX - cnt) goto overflow;
275 +
276 /* Update output count, end loop when fmt is exhausted */
277 - if (cnt >= 0) {
278 - if (l > INT_MAX - cnt) {
279 - if (!ferror(f)) errno = EOVERFLOW;
280 - cnt = -1;
281 - } else cnt += l;
282 - }
283 + cnt += l;
284 if (!*s) break;
285
286 /* Handle literal text and %% format specifiers */
287 for (a=s; *s && *s!='%'; s++);
288 - litpct = wcsspn(s, L"%")/2; /* Optimize %%%% runs */
289 - z = s+litpct;
290 - s += 2*litpct;
291 + for (z=s; s[0]=='%' && s[1]=='%'; z++, s+=2);
292 + if (z-a > INT_MAX-cnt) goto overflow;
293 l = z-a;
294 if (f) out(f, a, l);
295 if (l) continue;
296 @@ -222,9 +223,9 @@ static int wprintf_core(FILE *f, const wchar_t *fmt, va_list *ap, union arg *nl_
297 } else if (!l10n) {
298 w = f ? va_arg(*ap, int) : 0;
299 s++;
300 - } else return -1;
301 + } else goto inval;
302 if (w<0) fl|=LEFT_ADJ, w=-w;
303 - } else if ((w=getint(&s))<0) return -1;
304 + } else if ((w=getint(&s))<0) goto overflow;
305
306 /* Read precision */
307 if (*s=='.' && s[1]=='*') {
308 @@ -235,24 +236,29 @@ static int wprintf_core(FILE *f, const wchar_t *fmt, va_list *ap, union arg *nl_
309 } else if (!l10n) {
310 p = f ? va_arg(*ap, int) : 0;
311 s+=2;
312 - } else return -1;
313 + } else goto inval;
314 + xp = (p>=0);
315 } else if (*s=='.') {
316 s++;
317 p = getint(&s);
318 - } else p = -1;
319 + xp = 1;
320 + } else {
321 + p = -1;
322 + xp = 0;
323 + }
324
325 /* Format specifier state machine */
326 st=0;
327 do {
328 - if (OOB(*s)) return -1;
329 + if (OOB(*s)) goto inval;
330 ps=st;
331 st=states[st]S(*s++);
332 } while (st-1<STOP);
333 - if (!st) return -1;
334 + if (!st) goto inval;
335
336 /* Check validity of argument type (nl/normal) */
337 if (st==NOARG) {
338 - if (argpos>=0) return -1;
339 + if (argpos>=0) goto inval;
340 } else {
341 if (argpos>=0) nl_type[argpos]=st, arg=nl_arg[argpos];
342 else if (f) pop_arg(&arg, st, ap);
343 @@ -285,8 +291,9 @@ static int wprintf_core(FILE *f, const wchar_t *fmt, va_list *ap, union arg *nl_
344 continue;
345 case 'S':
346 a = arg.p;
347 - z = wmemchr(a, 0, p);
348 - if (z) p=z-a;
349 + z = a + wcsnlen(a, p<0 ? INT_MAX : p);
350 + if (p<0 && *z) goto overflow;
351 + p = z-a;
352 if (w<p) w=p;
353 if (!(fl&LEFT_ADJ)) fprintf(f, "%*s", w-p, "");
354 out(f, a, p);
355 @@ -298,9 +305,9 @@ static int wprintf_core(FILE *f, const wchar_t *fmt, va_list *ap, union arg *nl_
356 case 's':
357 if (!arg.p) arg.p = "(null)";
358 bs = arg.p;
359 - if (p<0) p = INT_MAX;
360 - for (i=l=0; l<p && (i=mbtowc(&wc, bs, MB_LEN_MAX))>0; bs+=i, l++);
361 + for (i=l=0; l<(p<0?INT_MAX:p) && (i=mbtowc(&wc, bs, MB_LEN_MAX))>0; bs+=i, l++);
362 if (i<0) return -1;
363 + if (p<0 && *bs) goto overflow;
364 p=l;
365 if (w<p) w=p;
366 if (!(fl&LEFT_ADJ)) fprintf(f, "%*s", w-p, "");
367 @@ -315,6 +322,7 @@ static int wprintf_core(FILE *f, const wchar_t *fmt, va_list *ap, union arg *nl_
368 continue;
369 }
370
371 + if (xp && p<0) goto overflow;
372 snprintf(charfmt, sizeof charfmt, "%%%s%s%s%s%s*.*%c%c",
373 "#"+!(fl & ALT_FORM),
374 "+"+!(fl & MARK_POS),
375 @@ -341,6 +349,13 @@ static int wprintf_core(FILE *f, const wchar_t *fmt, va_list *ap, union arg *nl_
376 for (; i<=NL_ARGMAX && !nl_type[i]; i++);
377 if (i<=NL_ARGMAX) return -1;
378 return 1;
379 +
380 +inval:
381 + errno = EINVAL;
382 + return -1;
383 +overflow:
384 + errno = EOVERFLOW;
385 + return -1;
386 }
387
388 int vfwprintf(FILE *restrict f, const wchar_t *restrict fmt, va_list ap)
389 --
390 cgit v0.11.2