This patch fixes security holes caused by potential buffer overflows in the implementation of the gzprintf() function in zlib 1.1.4. The security holes are fixed for platforms providing vsnprintf(3) and snprintf(3) only. This patch is derived from a prepared security patch, originally created by Kelledin . The OpenPKG project reduced the patch in size and fixed the configuration checks. diff -ru3 zlib-1.1.4.orig/configure zlib-1.1.4/configure --- zlib-1.1.4.orig/configure Wed Jul 8 20:19:35 1998 +++ zlib-1.1.4/configure Thu Feb 27 15:14:54 2003 @@ -155,7 +155,212 @@ echo "Checking for unistd.h... No." fi -cat > $test.c <$test.c < +#include + +#if (defined(__MSDOS__) || defined(_WINDOWS) || defined(_WIN32) || defined(__WIN32__) || defined(WIN32) || defined(__STDC__) || defined(__cplusplus) || defined(__OS2__)) && !defined(STDC) +# define STDC +#endif + +int main() +{ +#ifndef STDC + choke me +#endif + + return 0; +} +EOF + +if test "`($CC -c $CFLAGS $test.c) 2>&1`" = ""; then + echo "Checking whether to use vsnprintf() or snprintf()... using vsnprintf()" + + cat >$test.c < +#include + +int mytest(char *fmt, ...) +{ + char buf[20]; + va_list ap; + + va_start(ap, fmt); + vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + return 0; +} + +int main() +{ + return (mytest("Hello%d\n", 1)); +} +EOF + + if test "`($CC -c $CFLAGS $test.c) 2>&1`" = ""; then + CFLAGS="$CFLAGS -DHAS_vsnprintf" + echo "Checking for vsnprintf() in stdio.h... Yes." + + cat >$test.c < +#include + +int mytest(char *fmt, ...) +{ + int i; + char buf[20]; + va_list ap; + + va_start(ap, fmt); + i = vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + return 0; +} + +int main() +{ + return (mytest("Hello%d\n", 1)); +} +EOF + + if test "`($CC -c $CFLAGS $test.c) 2>&1`" = ""; then + CFLAGS="$CFLAGS -DHAS_vsnprintf_return" + echo "Checking for return value of vsnprintf()... Yes." + else + echo "Checking for return value of vsnprintf()... No." + echo " WARNING: apparently vsnprintf() does not return a value. zlib" + echo " can build but will be open to possible string-format security" + echo " vulnerabilities." + fi + else + echo "Checking for vsnprintf() in stdio.h... No." + echo " WARNING: vsnprintf() not found, falling back to vsprintf(). zlib" + echo " can build but will be open to possible buffer-overflow security" + echo " vulnerabilities." + + cat >$test.c < +#include + +int mytest(char *fmt, ...) +{ + int i; + char buf[20]; + va_list ap; + + va_start(ap, fmt); + i = vsprintf(buf, fmt, ap); + va_end(ap); + return 0; +} + +int main() +{ + return (mytest("Hello%d\n", 1)); +} +EOF + + if test "`($CC -c $CFLAGS $test.c) 2>&1`" = ""; then + CFLAGS="$CFLAGS -DHAS_vsprintf_return" + echo "Checking for return value of vsprintf()... Yes." + else + echo "Checking for return value of vsprintf()... No." + echo " WARNING: apparently vsprintf() does not return a value. zlib" + echo " can build but will be open to possible string-format security" + echo " vulnerabilities." + fi + fi +else + echo "Checking whether to use vsnprintf() or snprintf()... using snprintf()" + + cat >$test.c < +#include + +int mytest() +{ + char buf[20]; + + snprintf(buf, sizeof(buf), "%s", "foo"); + return 0; +} + +int main() +{ + return (mytest()); +} +EOF + + if test "`($CC -c $CFLAGS $test.c) 2>&1`" = ""; then + CFLAGS="$CFLAGS -DHAS_snprintf" + echo "Checking for snprintf() in stdio.h... Yes." + + cat >$test.c < +#include + +int mytest(char *fmt, ...) +{ + int i; + char buf[20]; + + i = snprintf(buf, sizeof(buf), "%s", "foo"); + return 0; +} + +int main() +{ + return (mytest()); +} +EOF + + if test "`($CC -c $CFLAGS $test.c) 2>&1`" = ""; then + CFLAGS="$CFLAGS -DHAS_snprintf_return" + echo "Checking for return value of snprintf()... Yes." + else + echo "Checking for return value of snprintf()... No." + echo " WARNING: apparently snprintf() does not return a value. zlib" + echo " can build but will be open to possible string-format security" + echo " vulnerabilities." + fi + else + echo "Checking for snprintf() in stdio.h... No." + echo " WARNING: snprintf() not found, falling back to sprintf(). zlib" + echo " can build but will be open to possible buffer-overflow security" + echo " vulnerabilities." + + cat >$test.c < +#include + +int mytest(char *fmt, ...) +{ + int i; + char buf[20]; + + i = sprintf(buf, "%s", "foo"); + return 0; +} + +int main() +{ + return (mytest()); +} +EOF + + if test "`($CC -c $CFLAGS $test.c) 2>&1`" = ""; then + CFLAGS="$CFLAGS -DHAS_sprintf_return" + echo "Checking for return value of sprintf()... Yes." + else + echo "Checking for return value of sprintf()... No." + echo " WARNING: apparently sprintf() does not return a value. zlib" + echo " can build but will be open to possible string-format security" + echo " vulnerabilities." + fi + fi +fi + +cat >$test.c < int main() { return 0; } EOF diff -ru3 zlib-1.1.4.orig/gzio.c zlib-1.1.4/gzio.c --- zlib-1.1.4.orig/gzio.c Mon Mar 11 14:16:01 2002 +++ zlib-1.1.4/gzio.c Thu Feb 27 14:29:26 2003 @@ -530,13 +530,31 @@ va_start(va, format); #ifdef HAS_vsnprintf +# ifdef HAS_vsnprintf_return + len = vsnprintf(buf, sizeof(buf), format, va); + va_end(va); + if (len <= 0 || len >= sizeof(buf)) + return 0; +# else (void)vsnprintf(buf, sizeof(buf), format, va); + va_end(va); + len = strlen(buf); + if (len <= 0) + return 0; +# endif #else +# ifdef HAS_vsprintf_return + len = vsprintf(buf, format, va); + va_end(va); + if (len <= 0 || len >= sizeof(buf)) + return 0; +# else (void)vsprintf(buf, format, va); -#endif va_end(va); len = strlen(buf); /* some *sprintf don't return the nb of bytes written */ if (len <= 0) return 0; +# endif +#endif return gzwrite(file, buf, (unsigned)len); } @@ -553,14 +571,31 @@ int len; #ifdef HAS_snprintf +# ifdef HAS_snprintf_return + len = snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); + if (len <= 0 || len >= sizeof(buf)) + return 0; +# else snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); + len = strlen(buf); + if (len <= 0) + return 0; +# endif #else +# ifdef HAS_sprintf_return + len = sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); + if (len <= 0 || len >= sizeof(buf)) + return 0; +# else sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); -#endif len = strlen(buf); /* old sprintf doesn't return the nb of bytes written */ if (len <= 0) return 0; +# endif +#endif return gzwrite(file, buf, len); }