gpg: Avoid infinite loop in uncompressing garbled packets.
authorWerner Koch <wk@gnupg.org>
Fri, 20 Jun 2014 08:39:26 +0000 (10:39 +0200)
committerWerner Koch <wk@gnupg.org>
Fri, 20 Jun 2014 08:41:38 +0000 (10:41 +0200)
* g10/compress.c (do_uncompress): Limit the number of extra FF bytes.
--

A packet like (a3 01 5b ff) leads to an infinite loop.  Using
--max-output won't help if it is a partial packet.  This patch
actually fixes a regression introduced on 1999-05-31 (c34c6769).
Actually it would be sufficient to stuff just one extra 0xff byte.
Given that this problem popped up only after 15 years, I feel safer to
allow for a very few FF bytes.

Thanks to Olivier Levillain and Florian Maury for their detailed
report.

g10/compress.c

index 6e412e9..0a6e09d 100644 (file)
@@ -164,7 +164,8 @@ do_uncompress( compress_filter_context_t *zfx, z_stream *zs,
               IOBUF a, size_t *ret_len )
 {
     int zrc;
-    int rc=0;
+    int rc = 0;
+    int leave = 0;
     size_t n;
     int nread, count;
     int refill = !zs->avail_in;
@@ -182,13 +183,14 @@ do_uncompress( compress_filter_context_t *zfx, z_stream *zs,
            nread = iobuf_read( a, zfx->inbuf + n, count );
            if( nread == -1 ) nread = 0;
            n += nread;
-           /* If we use the undocumented feature to suppress
-            * the zlib header, we have to give inflate an
-            * extra dummy byte to read */
-           if( nread < count && zfx->algo == 1 ) {
-               *(zfx->inbuf + n) = 0xFF; /* is it really needed ? */
-               zfx->algo1hack = 1;
+           /* Algo 1 has no zlib header which requires us to to give
+            * inflate an extra dummy byte to read. To be on the safe
+            * side we allow for up to 4 ff bytes.  */
+           if( nread < count && zfx->algo == 1 && zfx->algo1hack < 4) {
+               *(zfx->inbuf + n) = 0xFF;
+               zfx->algo1hack++;
                n++;
+                leave = 1;
            }
            zs->avail_in = n;
        }
@@ -208,7 +210,8 @@ do_uncompress( compress_filter_context_t *zfx, z_stream *zs,
            else
                log_fatal("zlib inflate problem: rc=%d\n", zrc );
        }
-    } while( zs->avail_out && zrc != Z_STREAM_END && zrc != Z_BUF_ERROR );
+    } while (zs->avail_out && zrc != Z_STREAM_END && zrc != Z_BUF_ERROR
+             && !leave);
 
     *ret_len = zfx->outbufsize - zs->avail_out;
     if( DBG_FILTER )