]> asedeno.scripts.mit.edu Git - PuTTY.git/commitdiff
Add a missing bounds check in the Deflate decompressor.
authorSimon Tatham <anakin@pobox.com>
Wed, 1 Oct 2014 18:33:45 +0000 (18:33 +0000)
committerSimon Tatham <anakin@pobox.com>
Wed, 1 Oct 2014 18:33:45 +0000 (18:33 +0000)
The symbol alphabet used for encoding ranges of backward distances in
a Deflate compressed block contains 32 symbol values, but two of them
(symbols 30 and 31) have no meaning, and hence it is an encoding error
for them to appear in a compressed block. If a compressed file did so
anyway, this decompressor would index past the end of the distcodes[]
array. Oops.

This is clearly a bug, but I don't believe it's a vulnerability. The
nonsense record we load from distcodes[] in this situation contains an
indeterminate bogus value for 'extrabits' (how many more bits to read
from the input stream to complete the backward distance) and also for
the offset to add to the backward distance after that. But neither of
these can lead to a buffer overflow: if extrabits is so big that
dctx->nbits (which is capped at 32) never exceeds it, then the
decompressor will simply swallow all further data without producing
any output, and otherwise the decompressor will consume _some_ number
of spare bits from the input, work out a backward distance and an
offset in the sliding window which will be utter nonsense and probably
out of bounds, but fortunately will then AND the offset with 0x7FFF at
the last minute, which makes it safe again. So I think the worst that
a malicious compressor can do is to cause the decompressor to generate
strange data, which of course it could do anyway if it wanted to by
sending that same data legally compressed.

[originally from svn r10278]

sshzlib.c

index 8a64e3563ee6318104d26a19b753dacd8385cd2a..c69edfb81f9a09648baa67c5cf909b3e83aaabcc 100644 (file)
--- a/sshzlib.c
+++ b/sshzlib.c
@@ -1234,6 +1234,8 @@ int zlib_decompress_block(void *handle, unsigned char *block, int len,
                goto finished;
            if (code == -2)
                goto decode_error;
+           if (code >= 30)            /* dist symbols 30 and 31 are invalid */
+               goto decode_error;
            dctx->state = GOTDISTSYM;
            dctx->sym = code;
            break;