diff options
| -rw-r--r-- | FAQ | 18 | ||||
| -rwxr-xr-x | configure | 17 | ||||
| -rw-r--r-- | gzwrite.c | 28 | ||||
| -rw-r--r-- | zlib.h | 26 | ||||
| -rw-r--r-- | zutil.c | 48 |
5 files changed, 95 insertions, 42 deletions
| @@ -258,15 +258,15 @@ The latest zlib FAQ is at http://zlib.net/zlib_faq.html | |||
| 258 | 33. Does zlib have any security vulnerabilities? | 258 | 33. Does zlib have any security vulnerabilities? |
| 259 | 259 | ||
| 260 | The only one that we are aware of is potentially in gzprintf(). If zlib is | 260 | The only one that we are aware of is potentially in gzprintf(). If zlib is |
| 261 | compiled to use sprintf() or vsprintf(), then there is no protection | 261 | compiled to use sprintf() or vsprintf(), which requires that ZLIB_INSECURE |
| 262 | against a buffer overflow of an 8K string space (or other value as set by | 262 | be defined, then there is no protection against a buffer overflow of an 8K |
| 263 | gzbuffer()), other than the caller of gzprintf() assuring that the output | 263 | string space (or other value as set by gzbuffer()), other than the caller |
| 264 | will not exceed 8K. On the other hand, if zlib is compiled to use | 264 | of gzprintf() assuring that the output will not exceed 8K. On the other |
| 265 | snprintf() or vsnprintf(), which should normally be the case, then there is | 265 | hand, if zlib is compiled to use snprintf() or vsnprintf(), which should |
| 266 | no vulnerability. The ./configure script will display warnings if an | 266 | normally be the case, then there is no vulnerability. The ./configure |
| 267 | insecure variation of sprintf() will be used by gzprintf(). Also the | 267 | script will display warnings if an insecure variation of sprintf() will be |
| 268 | zlibCompileFlags() function will return information on what variant of | 268 | used by gzprintf(). Also the zlibCompileFlags() function will return |
| 269 | sprintf() is used by gzprintf(). | 269 | information on what variant of sprintf() is used by gzprintf(). |
| 270 | 270 | ||
| 271 | If you don't have snprintf() or vsnprintf() and would like one, you can | 271 | If you don't have snprintf() or vsnprintf() and would like one, you can |
| 272 | find a good portable implementation in stb_sprintf.h here: | 272 | find a good portable implementation in stb_sprintf.h here: |
| @@ -92,6 +92,7 @@ warn=0 | |||
| 92 | debug=0 | 92 | debug=0 |
| 93 | address=0 | 93 | address=0 |
| 94 | memory=0 | 94 | memory=0 |
| 95 | insecure=0 | ||
| 95 | unknown=0 | 96 | unknown=0 |
| 96 | old_cc="$CC" | 97 | old_cc="$CC" |
| 97 | old_cflags="$CFLAGS" | 98 | old_cflags="$CFLAGS" |
| @@ -118,7 +119,7 @@ case "$1" in | |||
| 118 | -h* | --help) | 119 | -h* | --help) |
| 119 | echo 'usage:' | tee -a configure.log | 120 | echo 'usage:' | tee -a configure.log |
| 120 | echo ' configure [--const] [--zprefix] [--prefix=PREFIX] [--eprefix=EXPREFIX]' | tee -a configure.log | 121 | echo ' configure [--const] [--zprefix] [--prefix=PREFIX] [--eprefix=EXPREFIX]' | tee -a configure.log |
| 121 | echo ' [--static] [--64] [--libdir=LIBDIR] [--sharedlibdir=LIBDIR]' | tee -a configure.log | 122 | echo ' [--insecure] [--static] [--64] [--libdir=LIBDIR] [--sharedlibdir=LIBDIR]' | tee -a configure.log |
| 122 | echo ' [--includedir=INCLUDEDIR] [--archs="-arch i386 -arch x86_64"]' | tee -a configure.log | 123 | echo ' [--includedir=INCLUDEDIR] [--archs="-arch i386 -arch x86_64"]' | tee -a configure.log |
| 123 | exit 0 ;; | 124 | exit 0 ;; |
| 124 | -p*=* | --prefix=*) prefix=`echo $1 | sed 's/.*=//'`; shift ;; | 125 | -p*=* | --prefix=*) prefix=`echo $1 | sed 's/.*=//'`; shift ;; |
| @@ -146,6 +147,7 @@ case "$1" in | |||
| 146 | --sanitize) address=1; shift ;; | 147 | --sanitize) address=1; shift ;; |
| 147 | --address) address=1; shift ;; | 148 | --address) address=1; shift ;; |
| 148 | --memory) memory=1; shift ;; | 149 | --memory) memory=1; shift ;; |
| 150 | --insecure) insecure=1; shift ;; | ||
| 149 | *) unknown=1; echo "unknown option ignored: $1" | tee -a configure.log; shift;; | 151 | *) unknown=1; echo "unknown option ignored: $1" | tee -a configure.log; shift;; |
| 150 | esac | 152 | esac |
| 151 | done | 153 | done |
| @@ -256,6 +258,9 @@ if test "$gcc" -eq 1 && ($cc -c $test.c) >> configure.log 2>&1; then | |||
| 256 | if test $memory -eq 1; then | 258 | if test $memory -eq 1; then |
| 257 | CFLAGS="${CFLAGS} -g -fsanitize=memory -fno-omit-frame-pointer" | 259 | CFLAGS="${CFLAGS} -g -fsanitize=memory -fno-omit-frame-pointer" |
| 258 | fi | 260 | fi |
| 261 | if test $insecure -eq 1; then | ||
| 262 | CFLAGS="${CFLAGS} -DZLIB_INSECURE" | ||
| 263 | fi | ||
| 259 | if test $debug -eq 1; then | 264 | if test $debug -eq 1; then |
| 260 | CFLAGS="${CFLAGS} -DZLIB_DEBUG" | 265 | CFLAGS="${CFLAGS} -DZLIB_DEBUG" |
| 261 | SFLAGS="${SFLAGS} -DZLIB_DEBUG" | 266 | SFLAGS="${SFLAGS} -DZLIB_DEBUG" |
| @@ -740,7 +745,10 @@ EOF | |||
| 740 | echo " WARNING: vsnprintf() not found, falling back to vsprintf(). zlib" | tee -a configure.log | 745 | echo " WARNING: vsnprintf() not found, falling back to vsprintf(). zlib" | tee -a configure.log |
| 741 | echo " can build but will be open to possible buffer-overflow security" | tee -a configure.log | 746 | echo " can build but will be open to possible buffer-overflow security" | tee -a configure.log |
| 742 | echo " vulnerabilities." | tee -a configure.log | 747 | echo " vulnerabilities." | tee -a configure.log |
| 743 | 748 | if test $insecure -ne 1; then | |
| 749 | echo " The --insecure option must be provided to ./configure in order to" | tee -a configure.log | ||
| 750 | echo " compile using the insecure vsprintf() function." | tee -a configure.log | ||
| 751 | fi | ||
| 744 | echo >> configure.log | 752 | echo >> configure.log |
| 745 | cat >$test.c <<EOF | 753 | cat >$test.c <<EOF |
| 746 | #include <stdio.h> | 754 | #include <stdio.h> |
| @@ -824,7 +832,10 @@ EOF | |||
| 824 | echo " WARNING: snprintf() not found, falling back to sprintf(). zlib" | tee -a configure.log | 832 | echo " WARNING: snprintf() not found, falling back to sprintf(). zlib" | tee -a configure.log |
| 825 | echo " can build but will be open to possible buffer-overflow security" | tee -a configure.log | 833 | echo " can build but will be open to possible buffer-overflow security" | tee -a configure.log |
| 826 | echo " vulnerabilities." | tee -a configure.log | 834 | echo " vulnerabilities." | tee -a configure.log |
| 827 | 835 | if test $insecure -ne 1; then | |
| 836 | echo " The --insecure option must be provided to ./configure in order to" | tee -a configure.log | ||
| 837 | echo " compile using the insecure sprintf() function." | tee -a configure.log | ||
| 838 | fi | ||
| 828 | echo >> configure.log | 839 | echo >> configure.log |
| 829 | cat >$test.c <<EOF | 840 | cat >$test.c <<EOF |
| 830 | #include <stdio.h> | 841 | #include <stdio.h> |
| @@ -371,6 +371,9 @@ int ZEXPORT gzputs(gzFile file, const char *s) { | |||
| 371 | return len && put == 0 ? -1 : (int)put; | 371 | return len && put == 0 ? -1 : (int)put; |
| 372 | } | 372 | } |
| 373 | 373 | ||
| 374 | #if (((!defined(STDC) && !defined(Z_HAVE_STDARG_H)) || !defined(NO_vsnprintf)) && \ | ||
| 375 | (defined(STDC) || defined(Z_HAVE_STDARG_H) || !defined(NO_snprintf))) || \ | ||
| 376 | defined(ZLIB_INSECURE) | ||
| 374 | /* If the second half of the input buffer is occupied, write out the contents. | 377 | /* If the second half of the input buffer is occupied, write out the contents. |
| 375 | If there is any input remaining due to a non-blocking stall on write, move | 378 | If there is any input remaining due to a non-blocking stall on write, move |
| 376 | it to the start of the buffer. Return true if this did not open up the | 379 | it to the start of the buffer. Return true if this did not open up the |
| @@ -391,12 +394,20 @@ local int gz_vacate(gz_statep state) { | |||
| 391 | strm->next_in = state->in; | 394 | strm->next_in = state->in; |
| 392 | return strm->avail_in > state->size; | 395 | return strm->avail_in > state->size; |
| 393 | } | 396 | } |
| 397 | #endif | ||
| 394 | 398 | ||
| 395 | #if defined(STDC) || defined(Z_HAVE_STDARG_H) | 399 | #if defined(STDC) || defined(Z_HAVE_STDARG_H) |
| 396 | #include <stdarg.h> | 400 | #include <stdarg.h> |
| 397 | 401 | ||
| 398 | /* -- see zlib.h -- */ | 402 | /* -- see zlib.h -- */ |
| 399 | int ZEXPORTVA gzvprintf(gzFile file, const char *format, va_list va) { | 403 | int ZEXPORTVA gzvprintf(gzFile file, const char *format, va_list va) { |
| 404 | #if defined(NO_vsnprintf) && !defined(ZLIB_INSECURE) | ||
| 405 | #warning "vsnprintf() not available -- gzprintf() stub returns Z_STREAM_ERROR" | ||
| 406 | #warning "you can recompile with ZLIB_INSECURE defined to use vsprintf()" | ||
| 407 | /* prevent use of insecure vsprintf(), unless purposefully requested */ | ||
| 408 | (void)file, (void)format, (void)va; | ||
| 409 | return Z_STREAM_ERROR; | ||
| 410 | #else | ||
| 400 | int len, ret; | 411 | int len, ret; |
| 401 | char *next; | 412 | char *next; |
| 402 | gz_statep state; | 413 | gz_statep state; |
| @@ -470,6 +481,7 @@ int ZEXPORTVA gzvprintf(gzFile file, const char *format, va_list va) { | |||
| 470 | if (state->err && !state->again) | 481 | if (state->err && !state->again) |
| 471 | return state->err; | 482 | return state->err; |
| 472 | return len; | 483 | return len; |
| 484 | #endif | ||
| 473 | } | 485 | } |
| 474 | 486 | ||
| 475 | int ZEXPORTVA gzprintf(gzFile file, const char *format, ...) { | 487 | int ZEXPORTVA gzprintf(gzFile file, const char *format, ...) { |
| @@ -489,6 +501,17 @@ int ZEXPORTVA gzprintf(gzFile file, const char *format, int a1, int a2, int a3, | |||
| 489 | int a4, int a5, int a6, int a7, int a8, int a9, int a10, | 501 | int a4, int a5, int a6, int a7, int a8, int a9, int a10, |
| 490 | int a11, int a12, int a13, int a14, int a15, int a16, | 502 | int a11, int a12, int a13, int a14, int a15, int a16, |
| 491 | int a17, int a18, int a19, int a20) { | 503 | int a17, int a18, int a19, int a20) { |
| 504 | #if defined(NO_snprintf) && !defined(ZLIB_INSECURE) | ||
| 505 | #warning "snprintf() not available -- gzprintf() stub returns Z_STREAM_ERROR" | ||
| 506 | #warning "you can recompile with ZLIB_INSECURE defined to use sprintf()" | ||
| 507 | /* prevent use of insecure sprintf(), unless purposefully requested */ | ||
| 508 | (void)file, (void)format, (void)a1, (void)a2, (void)a3, (void)a4, (void)a5, | ||
| 509 | (void)a6, (void)a7, (void)a8, (void)a9, (void)a10, (void)a11, (void)a12, | ||
| 510 | (void)a13, (void)a14, (void)a15, (void)a16, (void)a17, (void)a18, | ||
| 511 | (void)a19, (void)a20; | ||
| 512 | return Z_STREAM_ERROR; | ||
| 513 | #else | ||
| 514 | int ret; | ||
| 492 | unsigned len, left; | 515 | unsigned len, left; |
| 493 | char *next; | 516 | char *next; |
| 494 | gz_statep state; | 517 | gz_statep state; |
| @@ -511,11 +534,11 @@ int ZEXPORTVA gzprintf(gzFile file, const char *format, int a1, int a2, int a3, | |||
| 511 | 534 | ||
| 512 | /* make sure we have some buffer space */ | 535 | /* make sure we have some buffer space */ |
| 513 | if (state->size == 0 && gz_init(state) == -1) | 536 | if (state->size == 0 && gz_init(state) == -1) |
| 514 | return state->error; | 537 | return state->err; |
| 515 | 538 | ||
| 516 | /* check for seek request */ | 539 | /* check for seek request */ |
| 517 | if (state->skip && gz_zero(state) == -1) | 540 | if (state->skip && gz_zero(state) == -1) |
| 518 | return state->error; | 541 | return state->err; |
| 519 | 542 | ||
| 520 | /* do the printf() into the input buffer, put length in len -- the input | 543 | /* do the printf() into the input buffer, put length in len -- the input |
| 521 | buffer is double-sized just for this function, so there is guaranteed to | 544 | buffer is double-sized just for this function, so there is guaranteed to |
| @@ -571,6 +594,7 @@ int ZEXPORTVA gzprintf(gzFile file, const char *format, int a1, int a2, int a3, | |||
| 571 | if (state->err && !state->again) | 594 | if (state->err && !state->again) |
| 572 | return state->err; | 595 | return state->err; |
| 573 | return (int)len; | 596 | return (int)len; |
| 597 | #endif | ||
| 574 | } | 598 | } |
| 575 | 599 | ||
| 576 | #endif | 600 | #endif |
| @@ -1239,13 +1239,14 @@ ZEXTERN uLong ZEXPORT zlibCompileFlags(void); | |||
| 1239 | 21: FASTEST -- deflate algorithm with only one, lowest compression level | 1239 | 21: FASTEST -- deflate algorithm with only one, lowest compression level |
| 1240 | 22,23: 0 (reserved) | 1240 | 22,23: 0 (reserved) |
| 1241 | 1241 | ||
| 1242 | The sprintf variant used by gzprintf (zero is best): | 1242 | The sprintf variant used by gzprintf (all zeros is best): |
| 1243 | 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format | 1243 | 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format |
| 1244 | 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure! | 1244 | 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() is not secure! |
| 1245 | 26: 0 = returns value, 1 = void -- 1 means inferred string length returned | 1245 | 26: 0 = returns value, 1 = void -- 1 means inferred string length returned |
| 1246 | 27: 0 = gzprintf() present, 1 = not -- 1 means gzprintf() returns an error | ||
| 1246 | 1247 | ||
| 1247 | Remainder: | 1248 | Remainder: |
| 1248 | 27-31: 0 (reserved) | 1249 | 28-31: 0 (reserved) |
| 1249 | */ | 1250 | */ |
| 1250 | 1251 | ||
| 1251 | #ifndef Z_SOLO | 1252 | #ifndef Z_SOLO |
| @@ -1527,7 +1528,11 @@ ZEXTERN z_size_t ZEXPORT gzfwrite(voidpc buf, z_size_t size, | |||
| 1527 | gzwrite() instead. | 1528 | gzwrite() instead. |
| 1528 | */ | 1529 | */ |
| 1529 | 1530 | ||
| 1531 | #if defined(STDC) || defined(Z_HAVE_STDARG_H) | ||
| 1530 | ZEXTERN int ZEXPORTVA gzprintf(gzFile file, const char *format, ...); | 1532 | ZEXTERN int ZEXPORTVA gzprintf(gzFile file, const char *format, ...); |
| 1533 | #else | ||
| 1534 | ZEXTERN int ZEXPORTVA gzprintf(); | ||
| 1535 | #endif | ||
| 1531 | /* | 1536 | /* |
| 1532 | Convert, format, compress, and write the arguments (...) to file under | 1537 | Convert, format, compress, and write the arguments (...) to file under |
| 1533 | control of the string format, as in fprintf. gzprintf returns the number of | 1538 | control of the string format, as in fprintf. gzprintf returns the number of |
| @@ -1535,11 +1540,16 @@ ZEXTERN int ZEXPORTVA gzprintf(gzFile file, const char *format, ...); | |||
| 1535 | of error. The number of uncompressed bytes written is limited to 8191, or | 1540 | of error. The number of uncompressed bytes written is limited to 8191, or |
| 1536 | one less than the buffer size given to gzbuffer(). The caller should assure | 1541 | one less than the buffer size given to gzbuffer(). The caller should assure |
| 1537 | that this limit is not exceeded. If it is exceeded, then gzprintf() will | 1542 | that this limit is not exceeded. If it is exceeded, then gzprintf() will |
| 1538 | return an error (0) with nothing written. In this case, there may also be a | 1543 | return an error (0) with nothing written. |
| 1539 | buffer overflow with unpredictable consequences, which is possible only if | 1544 | |
| 1540 | zlib was compiled with the insecure functions sprintf() or vsprintf(), | 1545 | In that last case, there may also be a buffer overflow with unpredictable |
| 1541 | because the secure snprintf() or vsnprintf() functions were not available. | 1546 | consequences, which is possible only if zlib was compiled with the insecure |
| 1542 | This can be determined using zlibCompileFlags(). | 1547 | functions sprintf() or vsprintf(), because the secure snprintf() and |
| 1548 | vsnprintf() functions were not available. That would only be the case for | ||
| 1549 | a non-ANSI C compiler. zlib may have been built without gzprintf() because | ||
| 1550 | secure functions were not available and having gzprintf() be insecure was | ||
| 1551 | not an option, in which case, gzprintf() returns Z_STREAM_ERROR. All of | ||
| 1552 | these possibilities can be determined using zlibCompileFlags(). | ||
| 1543 | 1553 | ||
| 1544 | If a Z_BUF_ERROR is returned, then nothing was written due to a stall on | 1554 | If a Z_BUF_ERROR is returned, then nothing was written due to a stall on |
| 1545 | the non-blocking write destination. | 1555 | the non-blocking write destination. |
| @@ -86,28 +86,36 @@ uLong ZEXPORT zlibCompileFlags(void) { | |||
| 86 | flags += 1L << 21; | 86 | flags += 1L << 21; |
| 87 | #endif | 87 | #endif |
| 88 | #if defined(STDC) || defined(Z_HAVE_STDARG_H) | 88 | #if defined(STDC) || defined(Z_HAVE_STDARG_H) |
| 89 | # ifdef NO_vsnprintf | 89 | # ifdef NO_vsnprintf |
| 90 | flags += 1L << 25; | 90 | # ifdef ZLIB_INSECURE |
| 91 | # ifdef HAS_vsprintf_void | 91 | flags += 1L << 25; |
| 92 | flags += 1L << 26; | 92 | # else |
| 93 | # endif | 93 | flags += 1L << 27; |
| 94 | # else | 94 | # endif |
| 95 | # ifdef HAS_vsnprintf_void | 95 | # ifdef HAS_vsprintf_void |
| 96 | flags += 1L << 26; | 96 | flags += 1L << 26; |
| 97 | # endif | 97 | # endif |
| 98 | # endif | 98 | # else |
| 99 | # ifdef HAS_vsnprintf_void | ||
| 100 | flags += 1L << 26; | ||
| 101 | # endif | ||
| 102 | # endif | ||
| 99 | #else | 103 | #else |
| 100 | flags += 1L << 24; | 104 | flags += 1L << 24; |
| 101 | # ifdef NO_snprintf | 105 | # ifdef NO_snprintf |
| 102 | flags += 1L << 25; | 106 | # ifdef ZLIB_INSECURE |
| 103 | # ifdef HAS_sprintf_void | 107 | flags += 1L << 25; |
| 104 | flags += 1L << 26; | 108 | # else |
| 105 | # endif | 109 | flags += 1L << 27; |
| 106 | # else | 110 | # endif |
| 107 | # ifdef HAS_snprintf_void | 111 | # ifdef HAS_sprintf_void |
| 108 | flags += 1L << 26; | 112 | flags += 1L << 26; |
| 109 | # endif | 113 | # endif |
| 110 | # endif | 114 | # else |
| 115 | # ifdef HAS_snprintf_void | ||
| 116 | flags += 1L << 26; | ||
| 117 | # endif | ||
| 118 | # endif | ||
| 111 | #endif | 119 | #endif |
| 112 | return flags; | 120 | return flags; |
| 113 | } | 121 | } |
