Fresh pull from upstream
[librecmc/librecmc.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