From 0a9e3e3d86140fd2f4eb83db0d18b1b6ea0fe7f1 Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Thu, 14 May 2009 16:17:47 +0000 Subject: [PATCH] MFB: Fixed #42663 (gzinflate() try to allocate all memory with truncated data) --- ext/zlib/tests/gzinflate-bug42663.phpt | 23 +++++++++++ ext/zlib/tests/gzinflate_length.phpt | 26 ++++++++++++ ext/zlib/zlib.c | 57 ++++++++++++++------------ 3 files changed, 79 insertions(+), 27 deletions(-) create mode 100644 ext/zlib/tests/gzinflate-bug42663.phpt create mode 100644 ext/zlib/tests/gzinflate_length.phpt 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 50b2f5bac7..7ac601f9c9 100644 --- a/ext/zlib/zlib.c +++ b/ext/zlib/zlib.c @@ -571,6 +571,20 @@ static PHP_FUNCTION(gzinflate) } plength = limit; + stream.zalloc = php_zlib_alloc; + stream.zfree = php_zlib_free; + 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 @@ -578,43 +592,32 @@ static PHP_FUNCTION(gzinflate) doubling it whenever it wasn't big enough that should be enaugh for all real life cases */ - - stream.zalloc = php_zlib_alloc; - stream.zfree = php_zlib_free; - 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); -- 2.50.1