From: Arnaud Le Blanc Date: Thu, 24 Jul 2008 14:38:37 +0000 (+0000) Subject: Fixed #42663 (gzinflate() try to allocate all memory with truncated data), not presen... X-Git-Tag: php-5.3.0alpha1~151 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=236b03985d81c2a8e65148b4fb28b0c3acd4f259;p=php Fixed #42663 (gzinflate() try to allocate all memory with truncated data), not present in HEAD. --- diff --git a/NEWS b/NEWS index b72fed5018..12853de397 100644 --- a/NEWS +++ b/NEWS @@ -283,6 +283,8 @@ PHP NEWS - Fixed bug #42737 (preg_split('//u') triggers a E_NOTICE with newlines). (Nuno) - Fixed bug #42736 (xmlrpc_server_call_method() crashes). (Tony) +- Fixed bug #42663 (gzinflate() try to allocate all memory with truncated + data). (Arnaud) - Fixed bug #42657 (ini_get() returns incorrect value when default is NULL). (Jani, Scott) - Fixed bug #42637 (SoapFault : Only http and https are allowed). (Bill Moran) 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-- + +--FILE-- + +--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-- + +--FILE-- + +--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);