summaryrefslogtreecommitdiff
path: root/openbsd-compat/bsd-snprintf.c
diff options
context:
space:
mode:
authorDamien Miller <djm@mindrot.org>2007-01-14 21:20:30 +1100
committerDamien Miller <djm@mindrot.org>2007-01-14 21:20:30 +1100
commit742cc1c19420db71275d3e8ef9fb86d96a463a4b (patch)
tree61b5cae9a33024d83df25a46fb386819294f0fe5 /openbsd-compat/bsd-snprintf.c
parente67ac00b9b76f126eec0ec4f0fc02ae66b5a1ad7 (diff)
- (djm) [openbsd-compat/bsd-snprintf.c] Fix integer overflow in return
value of snprintf replacement, similar to bugs in various libc implementations. This overflow is not exploitable in OpenSSH. While I'm fiddling with it, make it a fair bit faster by inlining the append-char routine; ok dtucker@
Diffstat (limited to 'openbsd-compat/bsd-snprintf.c')
-rw-r--r--openbsd-compat/bsd-snprintf.c164
1 files changed, 101 insertions, 63 deletions
diff --git a/openbsd-compat/bsd-snprintf.c b/openbsd-compat/bsd-snprintf.c
index 04651e1d4..cefb1d1ad 100644
--- a/openbsd-compat/bsd-snprintf.c
+++ b/openbsd-compat/bsd-snprintf.c
@@ -85,6 +85,11 @@
85 * 85 *
86 * Move #endif to make sure VA_COPY, LDOUBLE, etc are defined even 86 * Move #endif to make sure VA_COPY, LDOUBLE, etc are defined even
87 * if the C library has some snprintf functions already. 87 * if the C library has some snprintf functions already.
88 *
89 * Damien Miller (djm@mindrot.org) Jan 2007
90 * Fix integer overflows in return value.
91 * Make formatting quite a bit faster by inlining dopr_outch()
92 *
88 **************************************************************/ 93 **************************************************************/
89 94
90#include "includes.h" 95#include "includes.h"
@@ -112,6 +117,8 @@
112#include <stdarg.h> 117#include <stdarg.h>
113#include <stdlib.h> 118#include <stdlib.h>
114#include <string.h> 119#include <string.h>
120#include <limits.h>
121#include <errno.h>
115 122
116#ifdef HAVE_LONG_DOUBLE 123#ifdef HAVE_LONG_DOUBLE
117# define LDOUBLE long double 124# define LDOUBLE long double
@@ -159,17 +166,27 @@
159# define MAX(p,q) (((p) >= (q)) ? (p) : (q)) 166# define MAX(p,q) (((p) >= (q)) ? (p) : (q))
160#endif 167#endif
161 168
162static size_t dopr(char *buffer, size_t maxlen, const char *format, 169#define DOPR_OUTCH(buf, pos, buflen, thechar) \
163 va_list args_in); 170 do { \
164static void fmtstr(char *buffer, size_t *currlen, size_t maxlen, 171 if (++pos >= INT_MAX) { \
165 char *value, int flags, int min, int max); 172 errno = ERANGE; \
166static void fmtint(char *buffer, size_t *currlen, size_t maxlen, 173 return -1; \
167 LLONG value, int base, int min, int max, int flags); 174 if (pos < buflen) \
168static void fmtfp(char *buffer, size_t *currlen, size_t maxlen, 175 buf[pos] = thechar; \
169 LDOUBLE fvalue, int min, int max, int flags); 176 } \
170static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c); 177 } while (0)
171 178
172static size_t dopr(char *buffer, size_t maxlen, const char *format, va_list args_in) 179static int dopr(char *buffer, size_t maxlen, const char *format,
180 va_list args_in);
181static int fmtstr(char *buffer, size_t *currlen, size_t maxlen,
182 char *value, int flags, int min, int max);
183static int fmtint(char *buffer, size_t *currlen, size_t maxlen,
184 LLONG value, int base, int min, int max, int flags);
185static int fmtfp(char *buffer, size_t *currlen, size_t maxlen,
186 LDOUBLE fvalue, int min, int max, int flags);
187
188static int
189dopr(char *buffer, size_t maxlen, const char *format, va_list args_in)
173{ 190{
174 char ch; 191 char ch;
175 LLONG value; 192 LLONG value;
@@ -198,8 +215,8 @@ static size_t dopr(char *buffer, size_t maxlen, const char *format, va_list args
198 case DP_S_DEFAULT: 215 case DP_S_DEFAULT:
199 if (ch == '%') 216 if (ch == '%')
200 state = DP_S_FLAGS; 217 state = DP_S_FLAGS;
201 else 218 else
202 dopr_outch (buffer, &currlen, maxlen, ch); 219 DOPR_OUTCH(buffer, currlen, maxlen, ch);
203 ch = *format++; 220 ch = *format++;
204 break; 221 break;
205 case DP_S_FLAGS: 222 case DP_S_FLAGS:
@@ -298,7 +315,9 @@ static size_t dopr(char *buffer, size_t maxlen, const char *format, va_list args
298 value = va_arg (args, LLONG); 315 value = va_arg (args, LLONG);
299 else 316 else
300 value = va_arg (args, int); 317 value = va_arg (args, int);
301 fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags); 318 if (fmtint(buffer, &currlen, maxlen,
319 value, 10, min, max, flags) == -1)
320 return -1;
302 break; 321 break;
303 case 'o': 322 case 'o':
304 flags |= DP_F_UNSIGNED; 323 flags |= DP_F_UNSIGNED;
@@ -310,7 +329,9 @@ static size_t dopr(char *buffer, size_t maxlen, const char *format, va_list args
310 value = (long)va_arg (args, unsigned LLONG); 329 value = (long)va_arg (args, unsigned LLONG);
311 else 330 else
312 value = (long)va_arg (args, unsigned int); 331 value = (long)va_arg (args, unsigned int);
313 fmtint (buffer, &currlen, maxlen, value, 8, min, max, flags); 332 if (fmtint(buffer, &currlen, maxlen, value,
333 8, min, max, flags) == -1)
334 return -1;
314 break; 335 break;
315 case 'u': 336 case 'u':
316 flags |= DP_F_UNSIGNED; 337 flags |= DP_F_UNSIGNED;
@@ -322,7 +343,9 @@ static size_t dopr(char *buffer, size_t maxlen, const char *format, va_list args
322 value = (LLONG)va_arg (args, unsigned LLONG); 343 value = (LLONG)va_arg (args, unsigned LLONG);
323 else 344 else
324 value = (long)va_arg (args, unsigned int); 345 value = (long)va_arg (args, unsigned int);
325 fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags); 346 if (fmtint(buffer, &currlen, maxlen, value,
347 10, min, max, flags) == -1)
348 return -1;
326 break; 349 break;
327 case 'X': 350 case 'X':
328 flags |= DP_F_UP; 351 flags |= DP_F_UP;
@@ -336,15 +359,18 @@ static size_t dopr(char *buffer, size_t maxlen, const char *format, va_list args
336 value = (LLONG)va_arg (args, unsigned LLONG); 359 value = (LLONG)va_arg (args, unsigned LLONG);
337 else 360 else
338 value = (long)va_arg (args, unsigned int); 361 value = (long)va_arg (args, unsigned int);
339 fmtint (buffer, &currlen, maxlen, value, 16, min, max, flags); 362 if (fmtint(buffer, &currlen, maxlen, value,
363 16, min, max, flags) == -1)
364 return -1;
340 break; 365 break;
341 case 'f': 366 case 'f':
342 if (cflags == DP_C_LDOUBLE) 367 if (cflags == DP_C_LDOUBLE)
343 fvalue = va_arg (args, LDOUBLE); 368 fvalue = va_arg (args, LDOUBLE);
344 else 369 else
345 fvalue = va_arg (args, double); 370 fvalue = va_arg (args, double);
346 /* um, floating point? */ 371 if (fmtfp(buffer, &currlen, maxlen, fvalue,
347 fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags); 372 min, max, flags) == -1)
373 return -1;
348 break; 374 break;
349 case 'E': 375 case 'E':
350 flags |= DP_F_UP; 376 flags |= DP_F_UP;
@@ -353,7 +379,9 @@ static size_t dopr(char *buffer, size_t maxlen, const char *format, va_list args
353 fvalue = va_arg (args, LDOUBLE); 379 fvalue = va_arg (args, LDOUBLE);
354 else 380 else
355 fvalue = va_arg (args, double); 381 fvalue = va_arg (args, double);
356 fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags); 382 if (fmtfp(buffer, &currlen, maxlen, fvalue,
383 min, max, flags) == -1)
384 return -1;
357 break; 385 break;
358 case 'G': 386 case 'G':
359 flags |= DP_F_UP; 387 flags |= DP_F_UP;
@@ -362,10 +390,13 @@ static size_t dopr(char *buffer, size_t maxlen, const char *format, va_list args
362 fvalue = va_arg (args, LDOUBLE); 390 fvalue = va_arg (args, LDOUBLE);
363 else 391 else
364 fvalue = va_arg (args, double); 392 fvalue = va_arg (args, double);
365 fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags); 393 if (fmtfp(buffer, &currlen, maxlen, fvalue,
394 min, max, flags) == -1)
395 return -1;
366 break; 396 break;
367 case 'c': 397 case 'c':
368 dopr_outch (buffer, &currlen, maxlen, va_arg (args, int)); 398 DOPR_OUTCH(buffer, currlen, maxlen,
399 va_arg (args, int));
369 break; 400 break;
370 case 's': 401 case 's':
371 strvalue = va_arg (args, char *); 402 strvalue = va_arg (args, char *);
@@ -374,11 +405,15 @@ static size_t dopr(char *buffer, size_t maxlen, const char *format, va_list args
374 max = strlen(strvalue); 405 max = strlen(strvalue);
375 } 406 }
376 if (min > 0 && max >= 0 && min > max) max = min; 407 if (min > 0 && max >= 0 && min > max) max = min;
377 fmtstr (buffer, &currlen, maxlen, strvalue, flags, min, max); 408 if (fmtstr(buffer, &currlen, maxlen,
409 strvalue, flags, min, max) == -1)
410 return -1;
378 break; 411 break;
379 case 'p': 412 case 'p':
380 strvalue = va_arg (args, void *); 413 strvalue = va_arg (args, void *);
381 fmtint (buffer, &currlen, maxlen, (long) strvalue, 16, min, max, flags); 414 if (fmtint(buffer, &currlen, maxlen,
415 (long) strvalue, 16, min, max, flags) == -1)
416 return -1;
382 break; 417 break;
383 case 'n': 418 case 'n':
384 if (cflags == DP_C_SHORT) { 419 if (cflags == DP_C_SHORT) {
@@ -400,7 +435,7 @@ static size_t dopr(char *buffer, size_t maxlen, const char *format, va_list args
400 } 435 }
401 break; 436 break;
402 case '%': 437 case '%':
403 dopr_outch (buffer, &currlen, maxlen, ch); 438 DOPR_OUTCH(buffer, currlen, maxlen, ch);
404 break; 439 break;
405 case 'w': 440 case 'w':
406 /* not supported yet, treat as next char */ 441 /* not supported yet, treat as next char */
@@ -429,11 +464,12 @@ static size_t dopr(char *buffer, size_t maxlen, const char *format, va_list args
429 buffer[maxlen - 1] = '\0'; 464 buffer[maxlen - 1] = '\0';
430 } 465 }
431 466
432 return currlen; 467 return currlen < INT_MAX ? (int)currlen : -1;
433} 468}
434 469
435static void fmtstr(char *buffer, size_t *currlen, size_t maxlen, 470static int
436 char *value, int flags, int min, int max) 471fmtstr(char *buffer, size_t *currlen, size_t maxlen,
472 char *value, int flags, int min, int max)
437{ 473{
438 int padlen, strln; /* amount to pad */ 474 int padlen, strln; /* amount to pad */
439 int cnt = 0; 475 int cnt = 0;
@@ -453,24 +489,26 @@ static void fmtstr(char *buffer, size_t *currlen, size_t maxlen,
453 padlen = -padlen; /* Left Justify */ 489 padlen = -padlen; /* Left Justify */
454 490
455 while ((padlen > 0) && (cnt < max)) { 491 while ((padlen > 0) && (cnt < max)) {
456 dopr_outch (buffer, currlen, maxlen, ' '); 492 DOPR_OUTCH(buffer, *currlen, maxlen, ' ');
457 --padlen; 493 --padlen;
458 ++cnt; 494 ++cnt;
459 } 495 }
460 while (*value && (cnt < max)) { 496 while (*value && (cnt < max)) {
461 dopr_outch (buffer, currlen, maxlen, *value++); 497 DOPR_OUTCH(buffer, *currlen, maxlen, *value++);
462 ++cnt; 498 ++cnt;
463 } 499 }
464 while ((padlen < 0) && (cnt < max)) { 500 while ((padlen < 0) && (cnt < max)) {
465 dopr_outch (buffer, currlen, maxlen, ' '); 501 DOPR_OUTCH(buffer, *currlen, maxlen, ' ');
466 ++padlen; 502 ++padlen;
467 ++cnt; 503 ++cnt;
468 } 504 }
505 return 0;
469} 506}
470 507
471/* Have to handle DP_F_NUM (ie 0x and 0 alternates) */ 508/* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
472 509
473static void fmtint(char *buffer, size_t *currlen, size_t maxlen, 510static int
511fmtint(char *buffer, size_t *currlen, size_t maxlen,
474 LLONG value, int base, int min, int max, int flags) 512 LLONG value, int base, int min, int max, int flags)
475{ 513{
476 int signvalue = 0; 514 int signvalue = 0;
@@ -527,31 +565,32 @@ static void fmtint(char *buffer, size_t *currlen, size_t maxlen,
527 565
528 /* Spaces */ 566 /* Spaces */
529 while (spadlen > 0) { 567 while (spadlen > 0) {
530 dopr_outch (buffer, currlen, maxlen, ' '); 568 DOPR_OUTCH(buffer, *currlen, maxlen, ' ');
531 --spadlen; 569 --spadlen;
532 } 570 }
533 571
534 /* Sign */ 572 /* Sign */
535 if (signvalue) 573 if (signvalue)
536 dopr_outch (buffer, currlen, maxlen, signvalue); 574 DOPR_OUTCH(buffer, *currlen, maxlen, signvalue);
537 575
538 /* Zeros */ 576 /* Zeros */
539 if (zpadlen > 0) { 577 if (zpadlen > 0) {
540 while (zpadlen > 0) { 578 while (zpadlen > 0) {
541 dopr_outch (buffer, currlen, maxlen, '0'); 579 DOPR_OUTCH(buffer, *currlen, maxlen, '0');
542 --zpadlen; 580 --zpadlen;
543 } 581 }
544 } 582 }
545 583
546 /* Digits */ 584 /* Digits */
547 while (place > 0) 585 while (place > 0)
548 dopr_outch (buffer, currlen, maxlen, convert[--place]); 586 DOPR_OUTCH(buffer, *currlen, maxlen, convert[--place]);
549 587
550 /* Left Justified spaces */ 588 /* Left Justified spaces */
551 while (spadlen < 0) { 589 while (spadlen < 0) {
552 dopr_outch (buffer, currlen, maxlen, ' '); 590 DOPR_OUTCH(buffer, *currlen, maxlen, ' ');
553 ++spadlen; 591 ++spadlen;
554 } 592 }
593 return 0;
555} 594}
556 595
557static LDOUBLE abs_val(LDOUBLE value) 596static LDOUBLE abs_val(LDOUBLE value)
@@ -564,13 +603,13 @@ static LDOUBLE abs_val(LDOUBLE value)
564 return result; 603 return result;
565} 604}
566 605
567static LDOUBLE POW10(int exp) 606static LDOUBLE POW10(int val)
568{ 607{
569 LDOUBLE result = 1; 608 LDOUBLE result = 1;
570 609
571 while (exp) { 610 while (val) {
572 result *= 10; 611 result *= 10;
573 exp--; 612 val--;
574 } 613 }
575 614
576 return result; 615 return result;
@@ -604,7 +643,10 @@ static double my_modf(double x0, double *iptr)
604 } 643 }
605 644
606 if (i == 100) { 645 if (i == 100) {
607 /* yikes! the number is beyond what we can handle. What do we do? */ 646 /*
647 * yikes! the number is beyond what we can handle.
648 * What do we do?
649 */
608 (*iptr) = 0; 650 (*iptr) = 0;
609 return 0; 651 return 0;
610 } 652 }
@@ -623,8 +665,9 @@ static double my_modf(double x0, double *iptr)
623} 665}
624 666
625 667
626static void fmtfp (char *buffer, size_t *currlen, size_t maxlen, 668static int
627 LDOUBLE fvalue, int min, int max, int flags) 669fmtfp (char *buffer, size_t *currlen, size_t maxlen,
670 LDOUBLE fvalue, int min, int max, int flags)
628{ 671{
629 int signvalue = 0; 672 int signvalue = 0;
630 double ufvalue; 673 double ufvalue;
@@ -729,24 +772,24 @@ static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
729 772
730 if ((flags & DP_F_ZERO) && (padlen > 0)) { 773 if ((flags & DP_F_ZERO) && (padlen > 0)) {
731 if (signvalue) { 774 if (signvalue) {
732 dopr_outch (buffer, currlen, maxlen, signvalue); 775 DOPR_OUTCH(buffer, *currlen, maxlen, signvalue);
733 --padlen; 776 --padlen;
734 signvalue = 0; 777 signvalue = 0;
735 } 778 }
736 while (padlen > 0) { 779 while (padlen > 0) {
737 dopr_outch (buffer, currlen, maxlen, '0'); 780 DOPR_OUTCH(buffer, *currlen, maxlen, '0');
738 --padlen; 781 --padlen;
739 } 782 }
740 } 783 }
741 while (padlen > 0) { 784 while (padlen > 0) {
742 dopr_outch (buffer, currlen, maxlen, ' '); 785 DOPR_OUTCH(buffer, *currlen, maxlen, ' ');
743 --padlen; 786 --padlen;
744 } 787 }
745 if (signvalue) 788 if (signvalue)
746 dopr_outch (buffer, currlen, maxlen, signvalue); 789 DOPR_OUTCH(buffer, *currlen, maxlen, signvalue);
747 790
748 while (iplace > 0) 791 while (iplace > 0)
749 dopr_outch (buffer, currlen, maxlen, iconvert[--iplace]); 792 DOPR_OUTCH(buffer, *currlen, maxlen, iconvert[--iplace]);
750 793
751#ifdef DEBUG_SNPRINTF 794#ifdef DEBUG_SNPRINTF
752 printf("fmtfp: fplace=%d zpadlen=%d\n", fplace, zpadlen); 795 printf("fmtfp: fplace=%d zpadlen=%d\n", fplace, zpadlen);
@@ -757,41 +800,37 @@ static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
757 * char to print out. 800 * char to print out.
758 */ 801 */
759 if (max > 0) { 802 if (max > 0) {
760 dopr_outch (buffer, currlen, maxlen, '.'); 803 DOPR_OUTCH(buffer, *currlen, maxlen, '.');
761 804
762 while (zpadlen > 0) { 805 while (zpadlen > 0) {
763 dopr_outch (buffer, currlen, maxlen, '0'); 806 DOPR_OUTCH(buffer, *currlen, maxlen, '0');
764 --zpadlen; 807 --zpadlen;
765 } 808 }
766 809
767 while (fplace > 0) 810 while (fplace > 0)
768 dopr_outch (buffer, currlen, maxlen, fconvert[--fplace]); 811 DOPR_OUTCH(buffer, *currlen, maxlen,
812 fconvert[--fplace]);
769 } 813 }
770 814
771 while (padlen < 0) { 815 while (padlen < 0) {
772 dopr_outch (buffer, currlen, maxlen, ' '); 816 DOPR_OUTCH(buffer, *currlen, maxlen, ' ');
773 ++padlen; 817 ++padlen;
774 } 818 }
775} 819 return 0;
776
777static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c)
778{
779 if (*currlen < maxlen) {
780 buffer[(*currlen)] = c;
781 }
782 (*currlen)++;
783} 820}
784#endif /* !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF) */ 821#endif /* !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF) */
785 822
786#if !defined(HAVE_VSNPRINTF) 823#if !defined(HAVE_VSNPRINTF)
787int vsnprintf (char *str, size_t count, const char *fmt, va_list args) 824static int
825vsnprintf (char *str, size_t count, const char *fmt, va_list args)
788{ 826{
789 return dopr(str, count, fmt, args); 827 return dopr(str, count, fmt, args);
790} 828}
791#endif 829#endif
792 830
793#if !defined(HAVE_SNPRINTF) 831#if !defined(HAVE_SNPRINTF)
794int snprintf(char *str, size_t count, SNPRINTF_CONST char *fmt, ...) 832static int
833snprintf(char *str, size_t count, const char *fmt, ...)
795{ 834{
796 size_t ret; 835 size_t ret;
797 va_list ap; 836 va_list ap;
@@ -802,4 +841,3 @@ int snprintf(char *str, size_t count, SNPRINTF_CONST char *fmt, ...)
802 return ret; 841 return ret;
803} 842}
804#endif 843#endif
805