]> granicus.if.org Git - php/commitdiff
Fixed #42663 (gzinflate() try to allocate all memory with truncated data), not presen...
authorArnaud Le Blanc <lbarnaud@php.net>
Thu, 24 Jul 2008 14:38:37 +0000 (14:38 +0000)
committerArnaud Le Blanc <lbarnaud@php.net>
Thu, 24 Jul 2008 14:38:37 +0000 (14:38 +0000)
NEWS
ext/zlib/tests/gzinflate-bug42663.phpt [new file with mode: 0644]
ext/zlib/tests/gzinflate_length.phpt [new file with mode: 0644]
ext/zlib/zlib.c

diff --git a/NEWS b/NEWS
index b72fed5018cc7a2963d5ce2916c5e3433612cbb9..12853de397ff18c4d81eab3057361bb657d78c7e 100644 (file)
--- 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 (file)
index 0000000..dd53c78
--- /dev/null
@@ -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 (file)
index 0000000..436025d
--- /dev/null
@@ -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)
+
index 68d7db80b326a892a33358c049bf31216620a703..d78589e605a7bc2e34322d71ee309f819409cde8 100644 (file)
@@ -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);