diff options
author | Stanislav Malyshev <stas@php.net> | 2016-06-21 00:24:32 -0700 |
---|---|---|
committer | Stanislav Malyshev <stas@php.net> | 2016-06-21 00:24:32 -0700 |
commit | 2a65544f788654946bfe49e114efa748246fdd52 (patch) | |
tree | d97ac45ebbf1c9ebd3082c580c6db498e535b137 | |
parent | 18f30d702cc8714107ccdf9e6a67732e9e8a2ccf (diff) | |
parent | 7dde353ee79fcee73873cc19e1124704b94bd366 (diff) | |
download | php-git-2a65544f788654946bfe49e114efa748246fdd52.tar.gz |
Merge branch 'PHP-5.6.23' into PHP-7.0.8
* PHP-5.6.23: (24 commits)
iFixed bug #72446 - Integer Overflow in gdImagePaletteToTrueColor() resulting in heap overflow
update NEWS
fix tests
fix build
Fix bug #72455: Heap Overflow due to integer overflows
Fix bug #72434: ZipArchive class Use After Free Vulnerability in PHP's GC algorithm and unserialize
Fixed ##72433: Use After Free Vulnerability in PHP's GC algorithm and unserialize
Fix bug #72407: NULL Pointer Dereference at _gdScaleVert
Fix bug #72402: _php_mb_regex_ereg_replace_exec - double free
Fix bug #72298 pass2_no_dither out-of-bounds access
Fixed #72339 Integer Overflow in _gd2GetHeader() resulting in heap overflow
Fix bug #72262 - do not overflow int
Fix bug #72400 and #72403 - prevent signed int overflows for string lengths
Fix bug #72275: don't allow smart_str to overflow int
Fix bug #72340: Double Free Courruption in wddx_deserialize
update NEWS
Fix #66387: Stack overflow with imagefilltoborder
Fix bug #72321 - use efree() for emalloc allocation
5.6.23RC1
Fix bug #72140 (segfault after calling ERR_free_strings())
...
Conflicts:
configure.in
ext/mbstring/php_mbregex.c
ext/mcrypt/mcrypt.c
ext/spl/spl_array.c
ext/spl/spl_directory.c
ext/standard/php_smart_str.h
ext/standard/string.c
ext/standard/url.c
ext/wddx/wddx.c
ext/zip/php_zip.c
main/php_version.h
-rw-r--r-- | ext/gd/libgd/gd.c | 10 | ||||
-rw-r--r-- | ext/gd/libgd/gd_gd2.c | 7 | ||||
-rw-r--r-- | ext/gd/libgd/gd_interpolation.c | 3 | ||||
-rw-r--r-- | ext/gd/libgd/gd_topal.c | 2 | ||||
-rw-r--r-- | ext/gd/tests/bug72298.phpt | 15 | ||||
-rw-r--r-- | ext/gd/tests/bug72339.gd | bin | 0 -> 67108882 bytes | |||
-rw-r--r-- | ext/gd/tests/bug72339.phpt | 11 | ||||
-rw-r--r-- | ext/gd/tests/github_bug_215.phpt | 43 | ||||
-rw-r--r-- | ext/mbstring/php_mbregex.c | 1 | ||||
-rw-r--r-- | ext/mbstring/tests/bug72402.phpt | 17 | ||||
-rw-r--r-- | ext/mcrypt/mcrypt.c | 10 | ||||
-rw-r--r-- | ext/openssl/openssl.c | 3 | ||||
-rw-r--r-- | ext/phar/phar_object.c | 4 | ||||
-rw-r--r-- | ext/phar/tests/72321_1.zip | bin | 0 -> 250 bytes | |||
-rw-r--r-- | ext/phar/tests/72321_2.zip | bin | 0 -> 258 bytes | |||
-rw-r--r-- | ext/phar/tests/bug72321.phpt | 26 | ||||
-rw-r--r-- | ext/standard/tests/strings/bug72433.phpt | 32 | ||||
-rw-r--r-- | ext/standard/tests/strings/bug72434.phpt | 33 | ||||
-rw-r--r-- | ext/wddx/tests/bug72340.phpt | 24 | ||||
-rw-r--r-- | ext/wddx/wddx.c | 1 | ||||
-rw-r--r-- | ext/zip/php_zip.c | 9 |
21 files changed, 246 insertions, 5 deletions
diff --git a/ext/gd/libgd/gd.c b/ext/gd/libgd/gd.c index b427831672..17b0a1091b 100644 --- a/ext/gd/libgd/gd.c +++ b/ext/gd/libgd/gd.c @@ -131,6 +131,10 @@ gdImagePtr gdImageCreate (int sx, int sy) return NULL; } + if (overflow2(sizeof(unsigned char *), sx)) { + return NULL; + } + im = (gdImage *) gdCalloc(1, sizeof(gdImage)); /* Row-major ever since gd 1.3 */ @@ -1767,6 +1771,12 @@ void gdImageFillToBorder (gdImagePtr im, int x, int y, int border, int color) return; } + if (!im->trueColor) { + if ((color > (im->colorsTotal - 1)) || (border > (im->colorsTotal - 1)) || (color < 0)) { + return; + } + } + restoreAlphaBlending = im->alphaBlendingFlag; im->alphaBlendingFlag = 0; diff --git a/ext/gd/libgd/gd_gd2.c b/ext/gd/libgd/gd_gd2.c index 6726fee826..e954aafa68 100644 --- a/ext/gd/libgd/gd_gd2.c +++ b/ext/gd/libgd/gd_gd2.c @@ -138,11 +138,18 @@ static int _gd2GetHeader(gdIOCtxPtr in, int *sx, int *sy, int *cs, int *vers, in if (gd2_compressed(*fmt)) { nc = (*ncx) * (*ncy); GD2_DBG(php_gd_error("Reading %d chunk index entries", nc)); + if (overflow2(sizeof(t_chunk_info), nc)) { + goto fail1; + } sidx = sizeof(t_chunk_info) * nc; if (sidx <= 0) { goto fail1; } cidx = gdCalloc(sidx, 1); + if (cidx == NULL) { + goto fail1; + } + for (i = 0; i < nc; i++) { if (gdGetInt(&cidx[i].offset, in) != 1) { gdFree(cidx); diff --git a/ext/gd/libgd/gd_interpolation.c b/ext/gd/libgd/gd_interpolation.c index 6d703b8b30..83319966f9 100644 --- a/ext/gd/libgd/gd_interpolation.c +++ b/ext/gd/libgd/gd_interpolation.c @@ -1047,6 +1047,9 @@ static inline void _gdScaleVert (const gdImagePtr pSrc, const unsigned int src_w } contrib = _gdContributionsCalc(dst_height, src_height, (double)(dst_height) / (double)(src_height), pSrc->interpolation); + if (contrib == NULL) { + return; + } /* scale each column */ for (u = 0; u < dst_width - 1; u++) { _gdScaleCol(pSrc, src_width, pDst, dst_width, dst_height, u, contrib); diff --git a/ext/gd/libgd/gd_topal.c b/ext/gd/libgd/gd_topal.c index 0206860f05..d8dda45cb9 100644 --- a/ext/gd/libgd/gd_topal.c +++ b/ext/gd/libgd/gd_topal.c @@ -1329,7 +1329,7 @@ pass2_no_dither (j_decompress_ptr cinfo, /* If the pixel is transparent, we assign it the palette index that * will later be added at the end of the palette as the transparent * index. */ - if ((oim->transparent >= 0) && (oim->transparent == *(inptr - 1))) + if ((oim->transparent >= 0) && (oim->transparent == *inptr)) { *outptr++ = nim->colorsTotal; inptr++; diff --git a/ext/gd/tests/bug72298.phpt b/ext/gd/tests/bug72298.phpt new file mode 100644 index 0000000000..7fba241ed1 --- /dev/null +++ b/ext/gd/tests/bug72298.phpt @@ -0,0 +1,15 @@ +--TEST-- +Bug #72298: pass2_no_dither out-of-bounds access +--SKIPIF-- +<?php + if (!extension_loaded('gd')) die("skip gd extension not available\n"); +?> +--FILE-- +<?php +$img = imagecreatetruecolor (1 , 1); +imagecolortransparent($img, 0); +imagetruecolortopalette($img, false, 4); +?> +DONE +--EXPECT-- +DONE
\ No newline at end of file diff --git a/ext/gd/tests/bug72339.gd b/ext/gd/tests/bug72339.gd Binary files differnew file mode 100644 index 0000000000..0634c99005 --- /dev/null +++ b/ext/gd/tests/bug72339.gd diff --git a/ext/gd/tests/bug72339.phpt b/ext/gd/tests/bug72339.phpt new file mode 100644 index 0000000000..763ae71000 --- /dev/null +++ b/ext/gd/tests/bug72339.phpt @@ -0,0 +1,11 @@ +--TEST-- +Bug #72339 Integer Overflow in _gd2GetHeader() resulting in heap overflow +--SKIPIF-- +<?php if (!function_exists("imagecreatefromgd2")) print "skip"; ?> +--FILE-- +<?php imagecreatefromgd2(dirname(__FILE__) . DIRECTORY_SEPARATOR . "bug72339.gd"); ?> +--EXPECTF-- +Warning: imagecreatefromgd2(): gd warning: product of memory allocation multiplication would exceed INT_MAX, failing operation gracefully + in %sbug72339.php on line %d + +Warning: imagecreatefromgd2(): '%sbug72339.gd' is not a valid GD2 file in %sbug72339.php on line %d diff --git a/ext/gd/tests/github_bug_215.phpt b/ext/gd/tests/github_bug_215.phpt new file mode 100644 index 0000000000..f44a5401e1 --- /dev/null +++ b/ext/gd/tests/github_bug_215.phpt @@ -0,0 +1,43 @@ +--TEST-- +Github #215 (imagefilltoborder stack overflow when invalid pallete index used) +--SKIPIF-- +<?php +if (!extension_loaded("gd")) die("skip GD not present"); +?> +--FILE-- +<?php +$image = imagecreate( 10, 10 ); +$bgd = imagecolorallocate( $image, 0, 0, 0 ); +$border = imagecolorallocate( $image, 255, 0, 0 ); +$fillcolor = imagecolorallocate( $image, 255, 0, 0 ); + +/* Use unallocated color index */ +imagefilltoborder( $image, 0,0, $border+10, $fillcolor); +echo "#1 passes\n"; + +/* Use negative color index */ +imagefilltoborder( $image, 0,0, -$border, $fillcolor); +echo "#2 passes\n"; + + +/* Use unallocated color index */ +imagefilltoborder( $image, 0,0, $border, $fillcolor+10); +echo "#3 passes\n"; + +/* Use negative color index */ +imagefilltoborder( $image, 0,0, $border, -$fillcolor); +echo "#4 passes\n"; + + +/* Use negative color index */ +imagefilltoborder( $image, 0,0, $border+10, $fillcolor+10); +echo "#5 passes"; + + +?> +--EXPECT-- +#1 passes +#2 passes +#3 passes +#4 passes +#5 passes diff --git a/ext/mbstring/php_mbregex.c b/ext/mbstring/php_mbregex.c index 73c94da5e9..b59e0d9b0d 100644 --- a/ext/mbstring/php_mbregex.c +++ b/ext/mbstring/php_mbregex.c @@ -982,7 +982,6 @@ static void _php_mb_regex_ereg_replace_exec(INTERNAL_FUNCTION_PARAMETERS, OnigOp smart_str_free(&eval_buf); zval_ptr_dtor(&retval); } else { - efree(description); if (!EG(exception)) { php_error_docref(NULL, E_WARNING, "Unable to call custom replacement function"); } diff --git a/ext/mbstring/tests/bug72402.phpt b/ext/mbstring/tests/bug72402.phpt new file mode 100644 index 0000000000..abb290bf4d --- /dev/null +++ b/ext/mbstring/tests/bug72402.phpt @@ -0,0 +1,17 @@ +--TEST-- +Bug #72402: _php_mb_regex_ereg_replace_exec - double free +--SKIPIF-- +<?php extension_loaded('mbstring') or die('skip mbstring not available'); ?> +--FILE-- +<?php +function throwit() { + throw new Exception('it'); +} +$var10 = "throwit"; +try { + $var14 = mb_ereg_replace_callback("", $var10, ""); +} catch(Exception $e) {} +?> +DONE +--EXPECT-- +DONE
\ No newline at end of file diff --git a/ext/mcrypt/mcrypt.c b/ext/mcrypt/mcrypt.c index 073bfec775..fb5c638c97 100644 --- a/ext/mcrypt/mcrypt.c +++ b/ext/mcrypt/mcrypt.c @@ -637,6 +637,10 @@ PHP_FUNCTION(mcrypt_generic) if (mcrypt_enc_is_block_mode(pm->td) == 1) { /* It's a block algorithm */ block_size = mcrypt_enc_get_block_size(pm->td); data_size = ((((int)data_len - 1) / block_size) + 1) * block_size; + if (data_size <= 0) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Integer overflow in data size"); + RETURN_FALSE; + } data_str = zend_string_alloc(data_size, 0); memset(ZSTR_VAL(data_str), 0, data_size); memcpy(ZSTR_VAL(data_str), data, data_len); @@ -683,7 +687,11 @@ PHP_FUNCTION(mdecrypt_generic) if (mcrypt_enc_is_block_mode(pm->td) == 1) { /* It's a block algorithm */ block_size = mcrypt_enc_get_block_size(pm->td); data_size = ((((int)data_len - 1) / block_size) + 1) * block_size; - data_s = emalloc(data_size + 1); + if (data_size <= 0) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Integer overflow in data size"); + RETURN_FALSE; + } + data_s = emalloc((size_t)data_size + 1); memset(data_s, 0, data_size); memcpy(data_s, data, data_len); } else { /* It's not a block algorithm */ diff --git a/ext/openssl/openssl.c b/ext/openssl/openssl.c index 07f41ce8b9..2e8aa9a60d 100644 --- a/ext/openssl/openssl.c +++ b/ext/openssl/openssl.c @@ -1318,6 +1318,9 @@ PHP_MSHUTDOWN_FUNCTION(openssl) EVP_cleanup(); #if OPENSSL_VERSION_NUMBER >= 0x00090805f + /* prevent accessing locking callback from unloaded extension */ + CRYPTO_set_locking_callback(NULL); + /* free allocated error strings */ ERR_free_strings(); #endif diff --git a/ext/phar/phar_object.c b/ext/phar/phar_object.c index 7c9c3351aa..c57bdef3c6 100644 --- a/ext/phar/phar_object.c +++ b/ext/phar/phar_object.c @@ -4166,14 +4166,14 @@ static int phar_extract_file(zend_bool overwrite, phar_entry_info *entry, char * if (!php_stream_mkdir(fullpath, entry->flags & PHAR_ENT_PERM_MASK, PHP_STREAM_MKDIR_RECURSIVE, NULL)) { spprintf(error, 4096, "Cannot extract \"%s\", could not create directory \"%s\"", entry->filename, fullpath); efree(fullpath); - free(new_state.cwd); + efree(new_state.cwd); return FAILURE; } } else { if (!php_stream_mkdir(fullpath, 0777, PHP_STREAM_MKDIR_RECURSIVE, NULL)) { spprintf(error, 4096, "Cannot extract \"%s\", could not create directory \"%s\"", entry->filename, fullpath); efree(fullpath); - free(new_state.cwd); + efree(new_state.cwd); return FAILURE; } } diff --git a/ext/phar/tests/72321_1.zip b/ext/phar/tests/72321_1.zip Binary files differnew file mode 100644 index 0000000000..ebc44ea282 --- /dev/null +++ b/ext/phar/tests/72321_1.zip diff --git a/ext/phar/tests/72321_2.zip b/ext/phar/tests/72321_2.zip Binary files differnew file mode 100644 index 0000000000..de7ca266b8 --- /dev/null +++ b/ext/phar/tests/72321_2.zip diff --git a/ext/phar/tests/bug72321.phpt b/ext/phar/tests/bug72321.phpt new file mode 100644 index 0000000000..37aca19e82 --- /dev/null +++ b/ext/phar/tests/bug72321.phpt @@ -0,0 +1,26 @@ +--TEST-- +Phar: PHP bug #72321: invalid free in phar_extract_file() +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip"); ?> +--FILE-- +<?php +chdir(__DIR__); +mkdir("test72321"); +$phar = new PharData("72321_1.zip"); +$phar->extractTo("test72321"); +$phar = new PharData("72321_2.zip"); +try { +$phar->extractTo("test72321"); +} catch(PharException $e) { + print $e->getMessage()."\n"; +} +?> +DONE +--CLEAN-- +<?php unlink(__DIR__."/test72321/AAAAAAAAxxxxBBBBCCCCCCCCxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"); +rmdir(__DIR__."/test72321"); +?> +--EXPECTF-- +Warning: PharData::extractTo(): Not a directory in %s/bug72321.php on line %d +Extraction from phar "%s/72321_2.zip" failed: Cannot extract "AAAAAAAAxxxxBBBBCCCCCCCCxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/b/c", could not create directory "test72321/AAAAAAAAxxxxBBBBCCCCCCCCxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/b" +DONE
\ No newline at end of file diff --git a/ext/standard/tests/strings/bug72433.phpt b/ext/standard/tests/strings/bug72433.phpt new file mode 100644 index 0000000000..3a2c89701b --- /dev/null +++ b/ext/standard/tests/strings/bug72433.phpt @@ -0,0 +1,32 @@ +--TEST-- +Bug #72433: Use After Free Vulnerability in PHP's GC algorithm and unserialize +--FILE-- +<?php +// Fill any potential freed spaces until now. +$filler = array(); +for($i = 0; $i < 100; $i++) + $filler[] = ""; +// Create our payload and unserialize it. +$serialized_payload = 'a:3:{i:0;r:1;i:1;r:1;i:2;C:11:"ArrayObject":19:{x:i:0;r:1;;m:a:0:{}}}'; +$free_me = unserialize($serialized_payload); +// We need to increment the reference counter of our ArrayObject s.t. all reference counters of our unserialized array become 0. +$inc_ref_by_one = $free_me[2]; +// The call to gc_collect_cycles will free '$free_me'. +gc_collect_cycles(); +// We now have multiple freed spaces. Fill all of them. +$fill_freed_space_1 = "filler_zval_1"; +$fill_freed_space_2 = "filler_zval_2"; +var_dump($free_me); +?> +--EXPECTF-- +array(3) { + [0]=> + *RECURSION* + [1]=> + *RECURSION* + [2]=> + object(ArrayObject)#%d (1) { + ["storage":"ArrayObject":private]=> + *RECURSION* + } +} diff --git a/ext/standard/tests/strings/bug72434.phpt b/ext/standard/tests/strings/bug72434.phpt new file mode 100644 index 0000000000..1408b8f578 --- /dev/null +++ b/ext/standard/tests/strings/bug72434.phpt @@ -0,0 +1,33 @@ +--TEST-- +Bug #72434: ZipArchive class Use After Free Vulnerability in PHP's GC algorithm and unserialize +--SKIPIF-- +<?php +if(!class_exists('zip')) die('ZipArchive'); +?> +--FILE-- +<?php +// The following array will be serialized and this representation will be freed later on. +$free_me = array(new StdClass()); +// Create our payload and unserialize it. +$serialized_payload = 'a:3:{i:1;N;i:2;O:10:"ZipArchive":1:{s:8:"filename";'.serialize($free_me).'}i:1;R:4;}'; +$unserialized_payload = unserialize($serialized_payload); +gc_collect_cycles(); +// The reference counter for $free_me is at -1 for PHP 7 right now. +// Increment the reference counter by 1 -> rc is 0 +$a = $unserialized_payload[1]; +// Increment the reference counter by 1 again -> rc is 1 +$b = $a; +// Trigger free of $free_me (referenced by $m[1]). +unset($b); +$fill_freed_space_1 = "filler_zval_1"; +$fill_freed_space_2 = "filler_zval_2"; +$fill_freed_space_3 = "filler_zval_3"; +$fill_freed_space_4 = "filler_zval_4"; +debug_zval_dump($unserialized_payload[1]); +?> +--EXPECTF-- +array(1) refcount(1){ + [0]=> + object(stdClass)#%d (0) refcount(3){ + } +} diff --git a/ext/wddx/tests/bug72340.phpt b/ext/wddx/tests/bug72340.phpt new file mode 100644 index 0000000000..8d694ca52e --- /dev/null +++ b/ext/wddx/tests/bug72340.phpt @@ -0,0 +1,24 @@ +--TEST-- +Bug #72340: Double Free Courruption in wddx_deserialize +--SKIPIF-- +<?php +if (!extension_loaded("wddx")) print "skip"; +?> +--FILE-- +<?php +$xml = <<<EOF +<?xml version='1.0' ?> +<!DOCTYPE wddxPacket SYSTEM 'wddx_0100.dtd'> +<wddxPacket version='1.0'> + <array><var name="XXXXXXXX"><boolean value="none">TEST</boolean></var> + <var name="YYYYYYYY"><var name="ZZZZZZZZ"><var name="EZEZEZEZ"> + </var></var></var> + </array> +</wddxPacket> +EOF; +$array = wddx_deserialize($xml); +var_dump($array); +?> +--EXPECT-- +array(0) { +} diff --git a/ext/wddx/wddx.c b/ext/wddx/wddx.c index 330cb49f08..34b8eeb87f 100644 --- a/ext/wddx/wddx.c +++ b/ext/wddx/wddx.c @@ -1019,6 +1019,7 @@ static void php_wddx_process_data(void *user_data, const XML_Char *s, int len) zval_ptr_dtor(&ent->data); if (ent->varname) { efree(ent->varname); + ent->varname = NULL; } ZVAL_UNDEF(&ent->data); } diff --git a/ext/zip/php_zip.c b/ext/zip/php_zip.c index 88bb518442..bdcba78b21 100644 --- a/ext/zip/php_zip.c +++ b/ext/zip/php_zip.c @@ -958,6 +958,14 @@ static int php_zip_has_property(zval *object, zval *member, int type, void **cac } /* }}} */ +static HashTable *php_zip_get_gc(zval *object, zval **gc_data, int *gc_data_count) /* {{{ */ +{ + *gc_data = NULL; + *gc_data_count = 0; + return zend_std_get_properties(object); +} +/* }}} */ + static HashTable *php_zip_get_properties(zval *object)/* {{{ */ { ze_zip_object *obj; @@ -3014,6 +3022,7 @@ static PHP_MINIT_FUNCTION(zip) zip_object_handlers.clone_obj = NULL; zip_object_handlers.get_property_ptr_ptr = php_zip_get_property_ptr_ptr; + zip_object_handlers.get_gc = php_zip_get_gc; zip_object_handlers.get_properties = php_zip_get_properties; zip_object_handlers.read_property = php_zip_read_property; zip_object_handlers.has_property = php_zip_has_property; |