Fwd: buffer overrun in zlib 1.1.4

Kelledin kelledin+LFS at skarpsey.dyndns.org
Sun Feb 23 16:51:04 PST 2003


I thought we should take note of this and make sure we take 
appropriate measures in the LFS book.  This apparently hasn't 
spawned any thread on BugTraq, although I think it might be 
significant.

The first issue that's relevant to us:

1) vsnprintf() supposedly isn't used by default.  LFS supports 
vsnprintf(); we should make sure it's enabled.  This can be done 
by simply adding a "-DHAS_vsnprintf" to the CFLAGS we use to 
compile zlib:

	CFLAGS="$CFLAGS -fPIC -DHAS_vsnprintf" \
	    ./configure --prefix=/usr --shared

2) The code calling vsnprintf() silently truncates the data 
written to the buffer in question.  It is up to the calling app 
to detect the truncation by checking vsnprintf()'s return value, 
then take appropriate error-handling action if necessary.

At first glance, zlib does not do sufficient checking.  It does 
not gather the return value of vsnprintf() at all.  It instead 
tries to do an strlen() on the buffer filled by vsnprintf();  
this is VERY much the Wrong Thing(tm) to do:

   a) If the buffer would have a NULL character written in the     
      middle, this would cause the relevant code to return an 
      incorrect value.  This opens us up to a possible string 
      format vulnerability.

   b) If the buffer was not large enough to hold all the data,  
      that opens up the code to a bounds checking failure--AFAIK 
      vsnprintf() does not write a NULL character to the end of 
      the buffer in this case, so strlen() might end up trying to 
      check far beyond the end of the buffer and just might 
      possibly trigger a segfault before it hits a stray NULL 
      character.  Or it may never hit a stray NULL, thus might 
      wrap around to the beginning of memory, go all the way back 
      to its starting point, and keep checking forever.  Even if 
      neither of the two cases happens (and they usually won't 
      happen, but still...) it could take a lot more processor 
      time than necessary doing this check.

Attached below is a patch that should fix the problem for 
vsnprintf()-enabled builds.  We should all test it as much as 
possible...I've built zlib with it (and ensured that 
-DHAS_vsnprintf has the desired preprocessor effect), but I 
haven't done any testing on it yet.  Non-vsnprintf()-enabled 
builds are just stuck with a (possibly unavoidable) 
vulnerability, but we should at least fix it for Linux.

----------  Forwarded Message  ----------

Subject: buffer overrun in zlib 1.1.4
Date: Sat, 22 Feb 2003 00:05:47 +0000
From: Richard Kettlewell <rjk at greenend.org.uk>
To: bugtraq at securityfocus.com

zlib contains a function called gzprintf().  This is similar in
behaviour to fprintf() except that by default, this function
 will smash the stack if called with arguments that expand to
 more than Z_PRINTF_BUFSIZE (=4096 by default) bytes.

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.

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.

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.

I contacted zlib at gzip.org, and they say they're happy for me to
 post about this.

ttfn/rjk

    $ cat crashzlib.c
    #include <zlib.h>
    #include <errno.h>
    #include <stdio.h>

    int main(void) {
      gzFile f;
      int ret;

      if(!(f = gzopen("/dev/null", "w"))) {
        perror("/dev/null");
        exit(1);
      }
      ret = gzprintf(f, "%10240s", "");
      printf("gzprintf -> %d\n", ret);
      ret = gzclose(f);
      printf("gzclose -> %d [%d]\n", ret, errno);
      exit(0);
    }
    $ gcc -g -o crashzlib crashzlib.c -lz
    $ ./crashzlib
    Segmentation fault (core dumped)
    $
    $ dpkg -l zlib\* | grep ^i
    ii  zlib1g         1.1.4-1        compression library -
 runtime ii  zlib1g-dev     1.1.4-1        compression library -
 development $ gdb crashzlib core
    GNU gdb 2002-04-01-cvs
    Copyright 2002 Free Software Foundation, Inc.
    GDB is free software, covered by the GNU General Public
 License, and you are welcome to change it and/or distribute
 copies of it under certain conditions. Type "show copying" to
 see the conditions.
    There is absolutely no warranty for GDB.  Type "show
 warranty" for details. This GDB was configured as
 "i386-linux"...
    Core was generated by `           '.
    Program terminated with signal 11, Segmentation fault.
    Reading symbols from /usr/lib/libz.so.1...done.
    Loaded symbols for /usr/lib/libz.so.1
    Reading symbols from /lib/libc.so.6...done.
    Loaded symbols for /lib/libc.so.6
    Reading symbols from /lib/ld-linux.so.2...done.
    Loaded symbols for /lib/ld-linux.so.2
    #0  0x400944b2 in _IO_default_xsputn () from /lib/libc.so.6
    (gdb) bt
    #0  0x400944b2 in _IO_default_xsputn () from /lib/libc.so.6
    #1  0x4008b52a in _IO_padn () from /lib/libc.so.6
    #2  0x40075128 in vfprintf () from /lib/libc.so.6
    #3  0x4008c0c3 in vsprintf () from /lib/libc.so.6
    #4  0x4001c923 in gzprintf () from /usr/lib/libz.so.1
    #5  0x20202020 in ?? ()
    Cannot access memory at address 0x20202020
    (gdb) $

-------------------------------------------------------

-- 
Kelledin
"If a server crashes in a server farm and no one pings it, does 
it still cost four figures to fix?"

-- 
Unsubscribe: send email to listar at linuxfromscratch.org
and put 'unsubscribe lfs-dev' in the subject header of the message



More information about the lfs-dev mailing list