Subject: [libssh2] #240: Unhandled Z_BUF_ERROR inflating compressed stream

[libssh2] #240: Unhandled Z_BUF_ERROR inflating compressed stream

From: libssh2 Trac <trac_at_libssh2.stuge.se>
Date: Wed, 13 Jun 2012 14:13:57 -0000

#240: Unhandled Z_BUF_ERROR inflating compressed stream
----------------------+--------------------
 Reporter: steven | Owner:
     Type: defect | Status: new
 Priority: normal | Milestone: 1.5.0
Component: protocol | Version: 1.4.1
 Keywords: | Blocked By:
   Blocks: |
----------------------+--------------------
 When using libssh2 to perform an SFTP file transfer from the "JSCAPE MFT
 Server" (http://www.jscape.com) the transfer failed. The default JSCAPE
 configuration is to enforce zlib compression on SSH2 sessions so the
 session was compressed. The relevant part of the debug trace contained:
 {{{
  [libssh2] 1.052750 Transport: unhandled zlib error -5
  [libssh2] 1.052750 Failure Event: -29 - decompression failure
 }}}
 The trace comes from comp_method_zlib_decomp() in comp.c. The "unhandled
 zlib error -5" is the status returned from the zlib function inflate().
 The -5 status corresponds to "Z_BUF_ERROR".

 The inflate() function takes a pointer to a z_stream structure and
 "inflates" (decompresses) as much as it can. The relevant fields of the
 z_stream structure are:
 * next_in - pointer to the input buffer containing compressed data
 * avail_in - the number of bytes available at next_in
 * next_out - pointer to the output buffer to be filled with uncompressed
 data
 * avail_out - how much space available at next_out
 So, to decompress data you set up a z_stream struct with the relevant
 fields filled in and pass it to inflate(). On return the fields will have
 been updated so next_in and avail_in show how much compressed data is yet
 to be processed and next_out and avail_out show how much space is left in
 the output buffer.

 If the supplied output buffer is too small then on return there will be
 compressed data yet to be processed (avail_in != 0) and inflate() will
 return Z_OK. In this case the output buffer must be grown, avail_out
 updated and inflate() called again.

 If the supplied output buffer was big enough then on return the compressed
 data will have been exhausted (avail_in == 0) and inflate() will return
 Z_OK, so the data has all been uncompressed.

 There is a corner case where inflate() makes no progress. That is, there
 may be unprocessed compressed data and space available in the output
 buffer and yet the function does nothing. In this case inflate() will
 return Z_BUF_ERROR. From the zlib documentation and the source code it is
 not clear under what circumstances this happens. It could be that it needs
 to write multiple bytes (all in one go) from its internal state to the
 output buffer before processing the next chunk of input but but can't
 because there is not enough space (though my guesses as to the cause are
 not really relevant). Recovery from Z_BUF_ERROR is pretty simple - just
 grow the output buffer, update avail_out and call inflate() again.

 The comp_method_zlib_decomp() function does not handle the case when
 inflate() returns Z_BUF_ERROR. It treats it as a non-recoverable error and
 basically aborts the session.

 I've attached a patch to comp.c to the ticket that contains a proposed
 solution.

-- 
Ticket URL: <http://trac.libssh2.org/ticket/240>
libssh2 <http://trac.libssh2.org/>
C library for writing portable SSH2 clients
_______________________________________________
libssh2-devel http://cool.haxx.se/cgi-bin/mailman/listinfo/libssh2-devel
Received on 2012-06-13