Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions Zend/tests/bug70644.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
--TEST--
Bug #70644: trivial hash complexity DoS attack (plain array)
--FILE--
<?php

$a = [];
$s = 1 << 16;
for ($i = 0; count($a) < $s; $i += $s) {
$a[$i] = 0;
}

?>
--EXPECTF--

Fatal error: Uncaught HashCollisionError: Too many collisions in array in %s:%d
Stack trace:
#0 {main}
thrown in %s on line %d
24 changes: 24 additions & 0 deletions Zend/tests/bug70644_2.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
--TEST--
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should definitely go to json or there need to be at least skipif json ext is not there

Bug #70644: Trivial Hash complexity DoS (static array)
--FILE--
<?php

$elems = '';
for ($i = 0; $i < 2048; $i++) {
$elems .= $i * (1<<16) . " => 0, ";
}

$code = <<<PHP
\$x = 0;
return [\$x, $elems];
PHP;

try {
eval($code);
} catch (HashCollisionError $e) {
echo $e->getMessage(), "\n";
}

?>
--EXPECT--
Too many collisions in array
5 changes: 5 additions & 0 deletions Zend/zend_exceptions.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ ZEND_API zend_class_entry *zend_ce_type_error;
ZEND_API zend_class_entry *zend_ce_argument_count_error;
ZEND_API zend_class_entry *zend_ce_arithmetic_error;
ZEND_API zend_class_entry *zend_ce_division_by_zero_error;
ZEND_API zend_class_entry *zend_ce_hash_collision_error;

ZEND_API void (*zend_throw_exception_hook)(zval *ex);

Expand Down Expand Up @@ -871,6 +872,10 @@ void zend_register_default_exception(void) /* {{{ */
INIT_CLASS_ENTRY(ce, "DivisionByZeroError", NULL);
zend_ce_division_by_zero_error = zend_register_internal_class_ex(&ce, zend_ce_arithmetic_error);
zend_ce_division_by_zero_error->create_object = zend_default_exception_new;

INIT_CLASS_ENTRY(ce, "HashCollisionError", NULL);
zend_ce_hash_collision_error = zend_register_internal_class_ex(&ce, zend_ce_error);
zend_ce_hash_collision_error->create_object = zend_default_exception_new;
}
/* }}} */

Expand Down
1 change: 1 addition & 0 deletions Zend/zend_exceptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ extern ZEND_API zend_class_entry *zend_ce_type_error;
extern ZEND_API zend_class_entry *zend_ce_argument_count_error;
extern ZEND_API zend_class_entry *zend_ce_arithmetic_error;
extern ZEND_API zend_class_entry *zend_ce_division_by_zero_error;
extern ZEND_API zend_class_entry *zend_ce_hash_collision_error;

ZEND_API void zend_exception_set_previous(zend_object *exception, zend_object *add_previous);
ZEND_API void zend_exception_save(void);
Expand Down
29 changes: 19 additions & 10 deletions Zend/zend_execute.c
Original file line number Diff line number Diff line change
Expand Up @@ -1540,6 +1540,10 @@ static zend_always_inline zval *zend_fetch_dimension_address_inner(HashTable *ht
if (EXPECTED(Z_TYPE_P(dim) == IS_LONG)) {
hval = Z_LVAL_P(dim);
num_index:
if (type == BP_VAR_W) {
return zend_hash_index_add_or_return(ht, hval, &EG(uninitialized_zval));
}

ZEND_HASH_INDEX_FIND(ht, hval, retval, num_undef);
return retval;
num_undef:
Expand All @@ -1553,10 +1557,7 @@ static zend_always_inline zval *zend_fetch_dimension_address_inner(HashTable *ht
break;
case BP_VAR_RW:
zend_error(E_NOTICE,"Undefined offset: " ZEND_LONG_FMT, hval);
retval = zend_hash_index_update(ht, hval, &EG(uninitialized_zval));
break;
case BP_VAR_W:
retval = zend_hash_index_add_new(ht, hval, &EG(uninitialized_zval));
retval = zend_hash_index_update_exception(ht, hval, &EG(uninitialized_zval));
break;
}
} else if (EXPECTED(Z_TYPE_P(dim) == IS_STRING)) {
Expand All @@ -1567,6 +1568,17 @@ static zend_always_inline zval *zend_fetch_dimension_address_inner(HashTable *ht
}
}
str_index:
if (type == BP_VAR_W) {
retval = zend_hash_add_or_return(ht, offset_key, &EG(uninitialized_zval));
if (UNEXPECTED(Z_TYPE_P(retval) == IS_INDIRECT)) {
retval = Z_INDIRECT_P(retval);
if (UNEXPECTED(Z_TYPE_P(retval) == IS_UNDEF)) {
ZVAL_NULL(retval);
}
}
return retval;
}

retval = zend_hash_find(ht, offset_key);
if (retval) {
/* support for $GLOBALS[...] */
Expand All @@ -1583,10 +1595,9 @@ static zend_always_inline zval *zend_fetch_dimension_address_inner(HashTable *ht
break;
case BP_VAR_RW:
zend_error(E_NOTICE,"Undefined index: %s", ZSTR_VAL(offset_key));
/* break missing intentionally */
case BP_VAR_W:
ZVAL_NULL(retval);
break;
EMPTY_SWITCH_DEFAULT_CASE()
}
}
}
Expand All @@ -1601,11 +1612,9 @@ static zend_always_inline zval *zend_fetch_dimension_address_inner(HashTable *ht
break;
case BP_VAR_RW:
zend_error(E_NOTICE,"Undefined index: %s", ZSTR_VAL(offset_key));
retval = zend_hash_update(ht, offset_key, &EG(uninitialized_zval));
break;
case BP_VAR_W:
retval = zend_hash_add_new(ht, offset_key, &EG(uninitialized_zval));
retval = zend_hash_update_exception(ht, offset_key, &EG(uninitialized_zval));
break;
EMPTY_SWITCH_DEFAULT_CASE()
}
}
} else {
Expand Down
Loading