summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStanislav Malyshev <stas@php.net>2016-06-21 00:24:32 -0700
committerStanislav Malyshev <stas@php.net>2016-06-21 00:24:32 -0700
commit2a65544f788654946bfe49e114efa748246fdd52 (patch)
treed97ac45ebbf1c9ebd3082c580c6db498e535b137
parent18f30d702cc8714107ccdf9e6a67732e9e8a2ccf (diff)
parent7dde353ee79fcee73873cc19e1124704b94bd366 (diff)
downloadphp-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.c10
-rw-r--r--ext/gd/libgd/gd_gd2.c7
-rw-r--r--ext/gd/libgd/gd_interpolation.c3
-rw-r--r--ext/gd/libgd/gd_topal.c2
-rw-r--r--ext/gd/tests/bug72298.phpt15
-rw-r--r--ext/gd/tests/bug72339.gdbin0 -> 67108882 bytes
-rw-r--r--ext/gd/tests/bug72339.phpt11
-rw-r--r--ext/gd/tests/github_bug_215.phpt43
-rw-r--r--ext/mbstring/php_mbregex.c1
-rw-r--r--ext/mbstring/tests/bug72402.phpt17
-rw-r--r--ext/mcrypt/mcrypt.c10
-rw-r--r--ext/openssl/openssl.c3
-rw-r--r--ext/phar/phar_object.c4
-rw-r--r--ext/phar/tests/72321_1.zipbin0 -> 250 bytes
-rw-r--r--ext/phar/tests/72321_2.zipbin0 -> 258 bytes
-rw-r--r--ext/phar/tests/bug72321.phpt26
-rw-r--r--ext/standard/tests/strings/bug72433.phpt32
-rw-r--r--ext/standard/tests/strings/bug72434.phpt33
-rw-r--r--ext/wddx/tests/bug72340.phpt24
-rw-r--r--ext/wddx/wddx.c1
-rw-r--r--ext/zip/php_zip.c9
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
new file mode 100644
index 0000000000..0634c99005
--- /dev/null
+++ b/ext/gd/tests/bug72339.gd
Binary files differ
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
new file mode 100644
index 0000000000..ebc44ea282
--- /dev/null
+++ b/ext/phar/tests/72321_1.zip
Binary files differ
diff --git a/ext/phar/tests/72321_2.zip b/ext/phar/tests/72321_2.zip
new file mode 100644
index 0000000000..de7ca266b8
--- /dev/null
+++ b/ext/phar/tests/72321_2.zip
Binary files differ
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;