040-fix-integer-overflows-and-uncaught-eoverflow-in-printf-core.patch 12 KB

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