diff options
author | Arnaud Le Blanc <lbarnaud@php.net> | 2008-07-24 14:38:37 +0000 |
---|---|---|
committer | Arnaud Le Blanc <lbarnaud@php.net> | 2008-07-24 14:38:37 +0000 |
commit | 236b03985d81c2a8e65148b4fb28b0c3acd4f259 (patch) | |
tree | 90ad217daa1ee151a97f2663207b4b3a4798821b /ext/zlib | |
parent | ccc996f1d9a3dd97828882e49b60153d36fa3e63 (diff) | |
download | php-git-236b03985d81c2a8e65148b4fb28b0c3acd4f259.tar.gz |
Fixed #42663 (gzinflate() try to allocate all memory with truncated data), not present in HEAD.
Diffstat (limited to 'ext/zlib')
-rw-r--r-- | ext/zlib/tests/gzinflate-bug42663.phpt | 23 | ||||
-rw-r--r-- | ext/zlib/tests/gzinflate_length.phpt | 26 | ||||
-rw-r--r-- | ext/zlib/zlib.c | 57 |
3 files changed, 79 insertions, 27 deletions
diff --git a/ext/zlib/tests/gzinflate-bug42663.phpt b/ext/zlib/tests/gzinflate-bug42663.phpt new file mode 100644 index 0000000000..dd53c78f4e --- /dev/null +++ b/ext/zlib/tests/gzinflate-bug42663.phpt @@ -0,0 +1,23 @@ +--TEST-- +Bug #42663 (gzinflate() try to allocate all memory with truncated $data) +--SKIPIF-- +<?php if (!extension_loaded("zlib")) print "skip"; ?> +--FILE-- +<?php +// build a predictable string +$string = b''; +for($i=0; $i<30000; ++$i) $string .= (binary)$i . b' '; +var_dump(strlen($string)); +// deflate string +$deflated = gzdeflate($string,9); +var_dump(strlen($deflated)); +// truncate $deflated string +$truncated = substr($deflated, 0, 65535); +var_dump(strlen($truncated)); +// inflate $truncated string (check if it will not eat all memory) +gzinflate($truncated); +?> +--EXPECT-- +int(168890) +int(66743) +int(65535) diff --git a/ext/zlib/tests/gzinflate_length.phpt b/ext/zlib/tests/gzinflate_length.phpt new file mode 100644 index 0000000000..436025d13a --- /dev/null +++ b/ext/zlib/tests/gzinflate_length.phpt @@ -0,0 +1,26 @@ +--TEST-- +gzinflate() and $length argument +--SKIPIF-- +<?php if (!extension_loaded("zlib")) print "skip"; ?> +--FILE-- +<?php +$original = b'aaaaaaaaaaaaaaa'; +$packed=gzdeflate($original); +echo strlen($packed)." ".strlen($original)."\n"; +$unpacked=gzinflate($packed, strlen($original)); +if (strcmp($original,$unpacked)==0) echo "Strings are equal\n"; + +$unpacked=gzinflate($packed, strlen($original)*10); +if (strcmp($original,$unpacked)==0) echo "Strings are equal\n"; + +$unpacked=gzinflate($packed, 1); +if ($unpacked === false) echo "Failed (as expected)\n"; +?> +--EXPECTF-- +5 15 +Strings are equal +Strings are equal + +Warning: gzinflate(): insufficient memory in %s on line %d +Failed (as expected) + diff --git a/ext/zlib/zlib.c b/ext/zlib/zlib.c index 68d7db80b3..d78589e605 100644 --- a/ext/zlib/zlib.c +++ b/ext/zlib/zlib.c @@ -620,6 +620,20 @@ static PHP_FUNCTION(gzinflate) } plength = limit; + stream.zalloc = (alloc_func) Z_NULL; + stream.zfree = (free_func) Z_NULL; + stream.opaque = Z_NULL; + stream.avail_in = data_len + 1; /* there is room for \0 */ + stream.next_in = (Bytef *) data; + stream.total_out = 0; + + /* init with -MAX_WBITS disables the zlib internal headers */ + status = inflateInit2(&stream, -MAX_WBITS); + if (status != Z_OK) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", zError(status)); + RETURN_FALSE; + } + /* stream.avail_out wants to know the output data length if none was given as a parameter @@ -627,43 +641,32 @@ static PHP_FUNCTION(gzinflate) doubling it whenever it wasn't big enough that should be enaugh for all real life cases */ - - stream.zalloc = (alloc_func) Z_NULL; - stream.zfree = (free_func) Z_NULL; - do { length = plength ? plength : (unsigned long)data_len * (1 << factor++); s2 = (char *) erealloc(s1, length); - if (!s2 && s1) { - efree(s1); + if (!s2) { + if (s1) { + efree(s1); + } + inflateEnd(&stream); RETURN_FALSE; } + s1 = s2; - stream.next_in = (Bytef *) data; - stream.avail_in = (uInt) data_len + 1; /* there is room for \0 */ + stream.next_out = (Bytef *) &s2[stream.total_out]; + stream.avail_out = length - stream.total_out; + status = inflate(&stream, Z_NO_FLUSH); - stream.next_out = s2; - stream.avail_out = (uInt) length; + } while ((Z_BUF_ERROR == status || (Z_OK == status && stream.avail_in)) && !plength && factor < maxfactor); - /* init with -MAX_WBITS disables the zlib internal headers */ - status = inflateInit2(&stream, -MAX_WBITS); - if (status == Z_OK) { - status = inflate(&stream, Z_FINISH); - if (status != Z_STREAM_END) { - inflateEnd(&stream); - if (status == Z_OK) { - status = Z_BUF_ERROR; - } - } else { - status = inflateEnd(&stream); - } - } - s1 = s2; - - } while ((status == Z_BUF_ERROR) && (!plength) && (factor < maxfactor)); + inflateEnd(&stream); - if (status == Z_OK) { + if ((plength && Z_OK == status) || factor >= maxfactor) { + status = Z_MEM_ERROR; + } + + if (Z_STREAM_END == status || Z_OK == status) { s2 = erealloc(s2, stream.total_out + 1); /* room for \0 */ s2[ stream.total_out ] = '\0'; RETURN_STRINGL(s2, stream.total_out, 0); |