diff options
author | Nikita Popov <nikita.ppv@gmail.com> | 2019-10-02 12:42:46 +0200 |
---|---|---|
committer | Nikita Popov <nikita.ppv@gmail.com> | 2019-10-06 10:06:33 +0200 |
commit | 6623e7ac51f0bafe85e013f9aed5340199e80c10 (patch) | |
tree | 88a884f764f5a532996802ccbb74365a598884d5 | |
parent | b078ae6c01101f2f69cd5fb4c9b80c65a5164e04 (diff) | |
download | php-git-6623e7ac51f0bafe85e013f9aed5340199e80c10.tar.gz |
Add support for mbstring.regex_retry_limit
This is very similar to the existing mbstring.regex_stack_limit,
but for backtracking. The default value matches pcre.backtrack_limit.
Only used on libonig >= 2.8.0.
-rw-r--r-- | UPGRADING | 4 | ||||
-rw-r--r-- | ext/mbstring/mbstring.c | 5 | ||||
-rw-r--r-- | ext/mbstring/mbstring.h | 3 | ||||
-rw-r--r-- | ext/mbstring/php_mbregex.c | 9 | ||||
-rw-r--r-- | ext/mbstring/tests/retry_limit.phpt | 23 | ||||
-rw-r--r-- | php.ini-development | 5 | ||||
-rw-r--r-- | php.ini-production | 5 |
7 files changed, 53 insertions, 1 deletions
@@ -268,6 +268,10 @@ PHP 7.4 UPGRADE NOTES . Added mb_str_split() function, which provides the same functionality as str_split(), but operating on code points rather than bytes. RFC: https://wiki.php.net/rfc/mb_str_split + . Added mbstring.regex_retry_limit ini setting defaulting to 1000000. It + limits the amount of backtracking that may be performed during one mbregex + match and thus protects against exponential backtracking attacks (ReDOS). + This setting only takes effect when linking against oniguruma >= 2.8.0. - OPcache: . Support for preloading code has been added. diff --git a/ext/mbstring/mbstring.c b/ext/mbstring/mbstring.c index f1a617810a..a18d237df2 100644 --- a/ext/mbstring/mbstring.c +++ b/ext/mbstring/mbstring.c @@ -65,6 +65,7 @@ typedef void OnigMatchParam; #define onig_new_match_param() (NULL) #define onig_initialize_match_param(x) (void)(x) #define onig_set_match_stack_limit_size_of_match_param(x, y) +#define onig_set_retry_limit_in_match_of_match_param(x, y) #define onig_free_match_param(x) #define onig_search_with_param(reg, str, end, start, range, region, option, mp) \ onig_search(reg, str, end, start, range, region, option) @@ -1029,6 +1030,9 @@ static int _php_mb_match_regex(void *opaque, const char *str, size_t str_len) if (!ZEND_LONG_UINT_OVFL(MBSTRG(regex_stack_limit))) { onig_set_match_stack_limit_size_of_match_param(mp, (unsigned int)MBSTRG(regex_stack_limit)); } + if (!ZEND_LONG_UINT_OVFL(MBSTRG(regex_retry_limit))) { + onig_set_retry_limit_in_match_of_match_param(mp, (unsigned int)MBSTRG(regex_retry_limit)); + } /* search */ err = onig_search_with_param((php_mb_regex_t *)opaque, (const OnigUChar *)str, (const OnigUChar*)str + str_len, (const OnigUChar *)str, @@ -1495,6 +1499,7 @@ PHP_INI_BEGIN() strict_detection, zend_mbstring_globals, mbstring_globals) #if HAVE_MBREGEX STD_PHP_INI_ENTRY("mbstring.regex_stack_limit", "100000",PHP_INI_ALL, OnUpdateLong, regex_stack_limit, zend_mbstring_globals, mbstring_globals) + STD_PHP_INI_ENTRY("mbstring.regex_retry_limit", "1000000",PHP_INI_ALL, OnUpdateLong, regex_retry_limit, zend_mbstring_globals, mbstring_globals) #endif PHP_INI_END() /* }}} */ diff --git a/ext/mbstring/mbstring.h b/ext/mbstring/mbstring.h index 5a713e5496..eb2d0bce3f 100644 --- a/ext/mbstring/mbstring.h +++ b/ext/mbstring/mbstring.h @@ -170,6 +170,9 @@ ZEND_BEGIN_MODULE_GLOBALS(mbstring) zend_bool internal_encoding_set; zend_bool http_output_set; zend_bool http_input_set; +#if HAVE_MBREGEX + zend_long regex_retry_limit; +#endif ZEND_END_MODULE_GLOBALS(mbstring) #define MB_OVERLOAD_MAIL 1 diff --git a/ext/mbstring/php_mbregex.c b/ext/mbstring/php_mbregex.c index d315712781..366aad23cf 100644 --- a/ext/mbstring/php_mbregex.c +++ b/ext/mbstring/php_mbregex.c @@ -39,6 +39,7 @@ typedef void OnigMatchParam; #define onig_new_match_param() (NULL) #define onig_initialize_match_param(x) (void)(x) #define onig_set_match_stack_limit_size_of_match_param(x, y) +#define onig_set_retry_limit_in_match_of_match_param(x, y) #define onig_free_match_param(x) #define onig_search_with_param(reg, str, end, start, range, region, option, mp) \ onig_search(reg, str, end, start, range, region, option) @@ -874,6 +875,9 @@ static int _php_mb_onig_search(regex_t* reg, const OnigUChar* str, const OnigUCh if (!ZEND_LONG_UINT_OVFL(MBSTRG(regex_stack_limit))) { onig_set_match_stack_limit_size_of_match_param(mp, (unsigned int)MBSTRG(regex_stack_limit)); } + if (!ZEND_LONG_UINT_OVFL(MBSTRG(regex_retry_limit))) { + onig_set_retry_limit_in_match_of_match_param(mp, (unsigned int)MBSTRG(regex_retry_limit)); + } /* search */ err = onig_search_with_param(reg, str, end, start, range, region, option, mp); onig_free_match_param(mp); @@ -1395,9 +1399,12 @@ PHP_FUNCTION(mb_ereg_match) mp = onig_new_match_param(); onig_initialize_match_param(mp); - if(MBSTRG(regex_stack_limit) > 0 && MBSTRG(regex_stack_limit) < UINT_MAX) { + if (MBSTRG(regex_stack_limit) > 0 && MBSTRG(regex_stack_limit) < UINT_MAX) { onig_set_match_stack_limit_size_of_match_param(mp, (unsigned int)MBSTRG(regex_stack_limit)); } + if (MBSTRG(regex_retry_limit) > 0 && MBSTRG(regex_retry_limit) < UINT_MAX) { + onig_set_retry_limit_in_match_of_match_param(mp, (unsigned int)MBSTRG(regex_retry_limit)); + } /* match */ err = onig_match_with_param(re, (OnigUChar *)string, (OnigUChar *)(string + string_len), (OnigUChar *)string, NULL, 0, mp); onig_free_match_param(mp); diff --git a/ext/mbstring/tests/retry_limit.phpt b/ext/mbstring/tests/retry_limit.phpt new file mode 100644 index 0000000000..2d9d42a36f --- /dev/null +++ b/ext/mbstring/tests/retry_limit.phpt @@ -0,0 +1,23 @@ +--TEST-- +Oniguruma retry limit +--SKIPIF-- +<?php +extension_loaded('mbstring') or die('skip mbstring not available'); +if (!function_exists('mb_ereg')) die('skip mb_ereg not available'); +if (version_compare(MB_ONIGURUMA_VERSION, '6.8.0') < 0) { + die('skip requires Oniguruma 6.8.0'); +} +?> +--FILE-- +<?php + +$regex = 'A(B|C+)+D|AC+X'; +$str = 'ACCCCCCCCCCCCCCCCCCCX'; +var_dump(mb_ereg($regex, $str)); +ini_set('mbstring.regex_retry_limit', '100000'); +var_dump(mb_ereg($regex, $str)); + +?> +--EXPECT-- +int(1) +bool(false) diff --git a/php.ini-development b/php.ini-development index 4ac6c44b1e..7c8649d4c7 100644 --- a/php.ini-development +++ b/php.ini-development @@ -1692,6 +1692,11 @@ zend.assertions = 1 ; Default: 100000 ;mbstring.regex_stack_limit=100000 +; This directive specifies maximum retry count for mbstring regular expressions. It is similar +; to the pcre.backtrack_limit for PCRE. +; Default: 1000000 +;mbstring.regex_retry_limit=1000000 + [gd] ; Tell the jpeg decode to ignore warnings and try to create ; a gd image. The warning will then be displayed as notices diff --git a/php.ini-production b/php.ini-production index d47cf161e3..8dc9a32e00 100644 --- a/php.ini-production +++ b/php.ini-production @@ -1694,6 +1694,11 @@ zend.assertions = -1 ; Default: 100000 ;mbstring.regex_stack_limit=100000 +; This directive specifies maximum retry count for mbstring regular expressions. It is similar +; to the pcre.backtrack_limit for PCRE. +; Default: 1000000 +;mbstring.regex_retry_limit=1000000 + [gd] ; Tell the jpeg decode to ignore warnings and try to create ; a gd image. The warning will then be displayed as notices |