diff --git a/NEWS b/NEWS index 9ae8c7add120..d6bb6323ffff 100644 --- a/NEWS +++ b/NEWS @@ -24,6 +24,10 @@ PHP NEWS . Fixed bug GH-25268 (NULL php_libxml_ref_obj dereference in dom_objects_store_clone_obj when cloning Dom\Notation). (David Carlier) +- Filter: + . Fixed stack overflow in filter_var() and filter_var_array() with deeply + nested arrays. (Eyüp Can Akman) + - MBString: . Fixed stack overflow in mb_check_encoding() and mb_convert_encoding() with deeply nested arrays. (Eyüp Can Akman) diff --git a/ext/filter/filter.c b/ext/filter/filter.c index 7e1a03110994..a98fc56df240 100644 --- a/ext/filter/filter.c +++ b/ext/filter/filter.c @@ -393,6 +393,13 @@ static void php_zval_filter_recursive(zval *value, zend_long filter, zend_long f if (Z_TYPE_P(value) == IS_ARRAY) { zval *element; +#ifdef ZEND_CHECK_STACK_LIMIT + if (UNEXPECTED(zend_call_stack_overflowed(EG(stack_limit)))) { + zend_call_stack_size_error(); + return; + } +#endif + if (Z_IS_RECURSIVE_P(value)) { return; } @@ -403,6 +410,10 @@ static void php_zval_filter_recursive(zval *value, zend_long filter, zend_long f if (Z_TYPE_P(element) == IS_ARRAY) { SEPARATE_ARRAY(element); php_zval_filter_recursive(element, filter, flags, options, charset, copy); + if (EG(exception)) { + Z_UNPROTECT_RECURSION_P(value); + return; + } } else { php_zval_filter(element, filter, flags, options, charset, copy); } @@ -590,6 +601,10 @@ static void php_filter_array_handler(zval *input, HashTable *op_ht, zend_long op Z_TYPE_P(arg_elm) == IS_ARRAY ? 0 : zval_get_long(arg_elm), 0, FILTER_REQUIRE_SCALAR ); + if (EG(exception)) { + zval_ptr_dtor(&nval); + RETURN_THROWS(); + } zend_hash_update(Z_ARRVAL_P(return_value), arg_key, &nval); } } ZEND_HASH_FOREACH_END(); diff --git a/ext/filter/tests/filter_recursive_stack_limit.phpt b/ext/filter/tests/filter_recursive_stack_limit.phpt new file mode 100644 index 000000000000..fb8d4c6f3854 --- /dev/null +++ b/ext/filter/tests/filter_recursive_stack_limit.phpt @@ -0,0 +1,47 @@ +--TEST-- +Stack overflow in filter_var() and filter_var_array() with deeply nested arrays +--EXTENSIONS-- +filter +--SKIPIF-- + +--INI-- +zend.max_allowed_stack_size=256K +--FILE-- +getMessage(), "\n"; + var_dump($e->getPrevious()); +} +try { + filter_var_array(['a' => $deep, 'b' => $deep], ['a' => ['flags' => FILTER_REQUIRE_ARRAY], 'b' => ['flags' => FILTER_REQUIRE_ARRAY]]); +} catch (Error $e) { + echo $e->getMessage(), "\n"; + var_dump($e->getPrevious()); +} + +unset($e); +while (is_array($deep)) { + $deep = $deep[0]; +} +?> +--EXPECTF-- +Maximum call stack size of %d bytes (zend.max_allowed_stack_size - zend.reserved_stack_size) reached. Infinite recursion? +NULL +Maximum call stack size of %d bytes (zend.max_allowed_stack_size - zend.reserved_stack_size) reached. Infinite recursion? +NULL