]> granicus.if.org Git - php/commitdiff
Fix bug #72837 - integer overflow in bzdecompress caused heap corruption
authorStanislav Malyshev <stas@php.net>
Tue, 16 Aug 2016 06:17:26 +0000 (23:17 -0700)
committerStanislav Malyshev <stas@php.net>
Wed, 17 Aug 2016 05:55:41 +0000 (22:55 -0700)
ext/bz2/bz2.c

index 54b59f75d44b386b5ab9d461f2ba122760861abe..79ec3ec3fedf125ffbc9b938b6e55934b38bf34d 100644 (file)
@@ -196,7 +196,7 @@ php_stream_ops php_stream_bz2io_ops = {
 };
 
 /* {{{ Bzip2 stream openers */
-PHP_BZ2_API php_stream *_php_stream_bz2open_from_BZFILE(BZFILE *bz, 
+PHP_BZ2_API php_stream *_php_stream_bz2open_from_BZFILE(BZFILE *bz,
                                                                                                                const char *mode, php_stream *innerstream STREAMS_DC TSRMLS_DC)
 {
        struct php_bz2_stream_data_t *self;
@@ -574,15 +574,25 @@ static PHP_FUNCTION(bzdecompress)
                /* compression is better then 2:1, need to allocate more memory */
                bzs.avail_out = source_len;
                size = (bzs.total_out_hi32 * (unsigned int) -1) + bzs.total_out_lo32;
+               if (size > INT_MAX) {
+                       /* no reason to continue if we're going to drop it anyway */
+                       break;
+               }
                dest = safe_erealloc(dest, 1, bzs.avail_out+1, (size_t) size );
                bzs.next_out = dest + size;
        }
 
        if (error == BZ_STREAM_END || error == BZ_OK) {
                size = (bzs.total_out_hi32 * (unsigned int) -1) + bzs.total_out_lo32;
-               dest = safe_erealloc(dest, 1, (size_t) size, 1);
-               dest[size] = '\0';
-               RETVAL_STRINGL(dest, (int) size, 0);
+               if (size > INT_MAX) {
+                       php_error_docref(NULL TSRMLS_CC, E_WARNING, "Decompressed size too big, max is %d", INT_MAX);
+                       efree(dest);
+                       RETVAL_LONG(BZ_MEM_ERROR);
+               } else {
+                       dest = safe_erealloc(dest, 1, (size_t) size, 1);
+                       dest[size] = '\0';
+                       RETVAL_STRINGL(dest, (int) size, 0);
+               }
        } else { /* real error */
                efree(dest);
                RETVAL_LONG(error);