Merge branch 'PHP-5.5' into PHP-5.6.23

* PHP-5.5:
  Fixed 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
  Skip test which is 64bits only
  5.5.37 now

Conflicts:
	configure.in
	ext/mcrypt/mcrypt.c
	ext/spl/spl_directory.c
	main/php_version.h
This commit is contained in:
Stanislav Malyshev 2016-06-21 00:01:48 -07:00
commit 7dde353ee7
21 changed files with 450 additions and 243 deletions

View file

@ -13,5 +13,5 @@ var_dump(gc_collect_cycles());
echo "ok\n";
?>
--EXPECT--
int(1)
int(2)
ok

View file

@ -133,6 +133,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 */

View file

@ -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);

View file

@ -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);

View file

@ -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++;

View file

@ -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

BIN
ext/gd/tests/bug72339.gd Normal file

Binary file not shown.

View file

@ -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

View file

@ -953,7 +953,7 @@ static void _php_mb_regex_ereg_replace_exec(INTERNAL_FUNCTION_PARAMETERS, OnigOp
eval_buf.len = 0;
zval_dtor(&v);
} else if (is_callable) {
zval *retval_ptr;
zval *retval_ptr = NULL;
zval **args[1];
zval *subpats;
int i;
@ -972,13 +972,12 @@ static void _php_mb_regex_ereg_replace_exec(INTERNAL_FUNCTION_PARAMETERS, OnigOp
arg_replace_fci.param_count = 1;
arg_replace_fci.params = args;
arg_replace_fci.retval_ptr_ptr = &retval_ptr;
if (zend_call_function(&arg_replace_fci, &arg_replace_fci_cache TSRMLS_CC) == SUCCESS && arg_replace_fci.retval_ptr_ptr) {
if (zend_call_function(&arg_replace_fci, &arg_replace_fci_cache TSRMLS_CC) == SUCCESS && arg_replace_fci.retval_ptr_ptr && retval_ptr) {
convert_to_string_ex(&retval_ptr);
smart_str_appendl(&out_buf, Z_STRVAL_P(retval_ptr), Z_STRLEN_P(retval_ptr));
eval_buf.len = 0;
zval_ptr_dtor(&retval_ptr);
} else {
efree(description);
if (!EG(exception)) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to call custom replacement function");
}

View file

@ -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

View file

@ -661,6 +661,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 = (((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_s = emalloc(data_size + 1);
memset(data_s, 0, data_size);
memcpy(data_s, data, data_len);
@ -706,6 +710,10 @@ 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 = (((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_s = emalloc(data_size + 1);
memset(data_s, 0, data_size);
memcpy(data_s, data, data_len);

View file

@ -846,6 +846,16 @@ static HashTable* spl_array_get_debug_info(zval *obj, int *is_temp TSRMLS_DC) /*
}
/* }}} */
static HashTable *spl_array_get_gc(zval *object, zval ***gc_data, int *gc_data_count TSRMLS_DC) /* {{{ */
{
spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
*gc_data = &intern->array;
*gc_data_count = 1;
return zend_std_get_properties(object TSRMLS_CC);
}
/* }}} */
static zval *spl_array_read_property(zval *object, zval *member, int type, const zend_literal *key TSRMLS_DC) /* {{{ */
{
spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
@ -1975,6 +1985,7 @@ PHP_MINIT_FUNCTION(spl_array)
spl_handler_ArrayObject.get_properties = spl_array_get_properties;
spl_handler_ArrayObject.get_debug_info = spl_array_get_debug_info;
spl_handler_ArrayObject.get_gc = spl_array_get_gc;
spl_handler_ArrayObject.read_property = spl_array_read_property;
spl_handler_ArrayObject.write_property = spl_array_write_property;
spl_handler_ArrayObject.get_property_ptr_ptr = spl_array_get_property_ptr_ptr;

View file

@ -2948,6 +2948,10 @@ SPL_METHOD(SplFileObject, fread)
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Length parameter must be greater than 0");
RETURN_FALSE;
}
if (length > INT_MAX) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Length parameter must be no more than %d", INT_MAX);
RETURN_FALSE;
}
Z_STRVAL_P(return_value) = emalloc(length + 1);
Z_STRLEN_P(return_value) = php_stream_read(intern->u.file.stream, Z_STRVAL_P(return_value), length);

View file

@ -63,6 +63,9 @@
newlen = (d)->len + (n); \
if (newlen >= (d)->a) { \
(d)->a = newlen + SMART_STR_PREALLOC; \
if (UNEXPECTED((d)->a >= INT_MAX)) { \
zend_error(E_ERROR, "String size overflow"); \
} \
SMART_STR_DO_REALLOC(d, what); \
} \
} \

View file

@ -132,6 +132,9 @@ static char *php_bin2hex(const unsigned char *old, const size_t oldlen, size_t *
register unsigned char *result = NULL;
size_t i, j;
if (UNEXPECTED(oldlen * 2 * sizeof(char) > INT_MAX)) {
zend_error(E_ERROR, "String size overflow");
}
result = (unsigned char *) safe_emalloc(oldlen, 2 * sizeof(char), 1);
for (i = j = 0; i < oldlen; i++) {
@ -2608,6 +2611,7 @@ PHP_FUNCTION(quotemeta)
char *p, *q;
char c;
int old_len;
size_t new_len;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &old, &old_len) == FAILURE) {
return;
@ -2642,8 +2646,13 @@ PHP_FUNCTION(quotemeta)
}
}
*q = 0;
new_len = q - str;
if (UNEXPECTED(new_len > INT_MAX)) {
efree(str);
zend_error(E_ERROR, "String size overflow");
}
RETURN_STRINGL(erealloc(str, q - str + 1), q - str, 0);
RETURN_STRINGL(erealloc(str, new_len + 1), new_len, 0);
}
/* }}} */
@ -3495,7 +3504,7 @@ PHPAPI char *php_addcslashes(const char *str, int length, int *new_length, int s
char *source, *target;
char *end;
char c;
int newlen;
size_t newlen;
if (!wlength) {
wlength = strlen(what);
@ -3526,11 +3535,15 @@ PHPAPI char *php_addcslashes(const char *str, int length, int *new_length, int s
}
*target = 0;
newlen = target - new_str;
if (UNEXPECTED(newlen > INT_MAX)) {
efree(new_str);
zend_error(E_ERROR, "String size overflow");
}
if (target - new_str < length * 4) {
new_str = erealloc(new_str, newlen + 1);
}
if (new_length) {
*new_length = newlen;
*new_length = (int)newlen;
}
if (should_free) {
STR_FREE((char*)str);
@ -3582,6 +3595,9 @@ PHPAPI char *php_addslashes(char *str, int length, int *new_length, int should_f
*target = 0;
*new_length = target - new_str;
if (UNEXPECTED(*new_length < 0)) {
zend_error(E_ERROR, "String size overflow");
}
if (should_free) {
STR_FREE(str);
}
@ -4285,6 +4301,9 @@ PHP_FUNCTION(nl2br)
size_t repl_len = is_xhtml ? (sizeof("<br />") - 1) : (sizeof("<br>") - 1);
new_length = str_len + repl_cnt * repl_len;
if (UNEXPECTED(new_length > INT_MAX)) {
zend_error(E_ERROR, "String size overflow");
}
tmp = target = safe_emalloc(repl_cnt, repl_len, str_len + 1);
}

View file

@ -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*
}
}

View file

@ -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){
}
}

View file

@ -625,6 +625,10 @@ PHPAPI char *php_raw_url_encode(char const *s, int len, int *new_length)
if (new_length) {
*new_length = y;
}
if (UNEXPECTED(y > INT_MAX)) {
efree(str);
zend_error(E_ERROR, "String size overflow");
}
return ((char *) str);
}
/* }}} */

View file

@ -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) {
}

View file

@ -1094,6 +1094,9 @@ static void php_wddx_process_data(void *user_data, const XML_Char *s, int len)
break;
case ST_BOOLEAN:
if(!ent->data) {
break;
}
if (!strcmp(s, "true")) {
Z_LVAL_P(ent->data) = 1;
} else if (!strcmp(s, "false")) {
@ -1102,6 +1105,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;
}
ent->data = NULL;
}

View file

@ -1042,6 +1042,14 @@ static int php_zip_has_property(zval *object, zval *member, int type KEY_ARG_DC
}
/* }}} */
static HashTable *php_zip_get_gc(zval *object, zval ***gc_data, int *gc_data_count TSRMLS_DC) /* {{{ */
{
*gc_data = NULL;
*gc_data_count = 0;
return zend_std_get_properties(object TSRMLS_CC);
}
/* }}} */
static HashTable *php_zip_get_properties(zval *object TSRMLS_DC)/* {{{ */
{
ze_zip_object *obj;
@ -3039,6 +3047,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;