diff options
author | Stanislav Malyshev <stas@php.net> | 2019-04-01 00:32:49 -0700 |
---|---|---|
committer | Stanislav Malyshev <stas@php.net> | 2019-04-01 00:32:49 -0700 |
commit | 63e0c220374733947ed869597ecf81ea2de138b2 (patch) | |
tree | b0fa5adf57f3cf377dc9020a56f2bc9376a8fee4 | |
parent | 9a06876072b9ccb023d4a14426ccb587f10882f3 (diff) | |
parent | 0eea9a642941ab5d4c612f8092f186977afbb73e (diff) | |
download | php-git-63e0c220374733947ed869597ecf81ea2de138b2.tar.gz |
Merge branch 'PHP-7.4'
* PHP-7.4:
Unfortunately, travis CI has old oniguruma library
Update NEWS & UPGRADING
Add fallbacks for older oniguruma versions
Add mbstring.regex_stack_limit to php.ini-*
Implement RF bug #72777 - ensure stack limits on mbstring functions.
-rw-r--r-- | ext/mbstring/mbstring.c | 29 | ||||
-rw-r--r-- | ext/mbstring/mbstring.h | 1 | ||||
-rw-r--r-- | ext/mbstring/php_mbregex.c | 46 | ||||
-rw-r--r-- | ext/mbstring/tests/mbregex_stack_limit.phpt | 26 | ||||
-rw-r--r-- | ext/mbstring/tests/mbregex_stack_limit2.phpt | 27 | ||||
-rw-r--r-- | php.ini-development | 5 | ||||
-rw-r--r-- | php.ini-production | 5 |
7 files changed, 131 insertions, 8 deletions
diff --git a/ext/mbstring/mbstring.c b/ext/mbstring/mbstring.c index fce4dc5207..3cd6449c43 100644 --- a/ext/mbstring/mbstring.c +++ b/ext/mbstring/mbstring.c @@ -60,6 +60,17 @@ # include "php_onig_compat.h" # include <oniguruma.h> # undef UChar +#if ONIGURUMA_VERSION_INT < 60800 +typedef void OnigMatchParam; +#define onig_new_match_param() (NULL) +#define onig_initialize_match_param(x) +#define onig_set_match_stack_limit_size_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) +#define onig_match_with_param(re, str, end, at, region, option, mp) \ +onig_match(re, str, end, at, region, option) +#endif #else # include "ext/pcre/php_pcre.h" #endif @@ -1012,9 +1023,18 @@ static void *_php_mb_compile_regex(const char *pattern) /* {{{ _php_mb_match_regex */ static int _php_mb_match_regex(void *opaque, const char *str, size_t str_len) { - return onig_search((php_mb_regex_t *)opaque, (const OnigUChar *)str, - (const OnigUChar*)str + str_len, (const OnigUChar *)str, - (const OnigUChar*)str + str_len, NULL, ONIG_OPTION_NONE) >= 0; + OnigMatchParam *mp = onig_new_match_param(); + int err; + onig_initialize_match_param(mp); + 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)); + } + /* search */ + err = onig_search_with_param((php_mb_regex_t *)opaque, (const OnigUChar *)str, + (const OnigUChar*)str + str_len, (const OnigUChar *)str, + (const OnigUChar*)str + str_len, NULL, ONIG_OPTION_NONE, mp); + onig_free_match_param(mp); + return err >= 0; } /* }}} */ @@ -1485,6 +1505,9 @@ PHP_INI_BEGIN() PHP_INI_ALL, OnUpdateBool, 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) +#endif PHP_INI_END() /* }}} */ diff --git a/ext/mbstring/mbstring.h b/ext/mbstring/mbstring.h index a39d7b85c2..712545591b 100644 --- a/ext/mbstring/mbstring.h +++ b/ext/mbstring/mbstring.h @@ -164,6 +164,7 @@ ZEND_BEGIN_MODULE_GLOBALS(mbstring) void *http_output_conv_mimetypes; #if HAVE_MBREGEX struct _zend_mb_regex_globals *mb_regex_globals; + zend_long regex_stack_limit; #endif zend_string *last_used_encoding_name; const mbfl_encoding *last_used_encoding; diff --git a/ext/mbstring/php_mbregex.c b/ext/mbstring/php_mbregex.c index 02d7e21378..3b8466fbe7 100644 --- a/ext/mbstring/php_mbregex.c +++ b/ext/mbstring/php_mbregex.c @@ -34,6 +34,18 @@ #include <oniguruma.h> #undef UChar +#if ONIGURUMA_VERSION_INT < 60800 +typedef void OnigMatchParam; +#define onig_new_match_param() (NULL) +#define onig_initialize_match_param(x) +#define onig_set_match_stack_limit_size_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) +#define onig_match_with_param(re, str, end, at, region, option, mp) \ + onig_match(re, str, end, at, region, option) +#endif + ZEND_EXTERN_MODULE_GLOBALS(mbstring) struct _zend_mb_regex_globals { @@ -853,6 +865,23 @@ PHP_FUNCTION(mb_regex_encoding) } /* }}} */ +/* {{{ _php_mb_onig_search */ +static int _php_mb_onig_search(regex_t* reg, const OnigUChar* str, const OnigUChar* end, const OnigUChar* start, + const OnigUChar* range, OnigRegion* region, OnigOptionType option) { + OnigMatchParam *mp = onig_new_match_param(); + int err; + onig_initialize_match_param(mp); + 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)); + } + /* search */ + err = onig_search_with_param(reg, str, end, start, range, region, option, mp); + onig_free_match_param(mp); + return err; +} +/* }}} */ + + /* {{{ _php_mb_regex_ereg_exec */ static void _php_mb_regex_ereg_exec(INTERNAL_FUNCTION_PARAMETERS, int icase) { @@ -904,7 +933,7 @@ static void _php_mb_regex_ereg_exec(INTERNAL_FUNCTION_PARAMETERS, int icase) regs = onig_region_new(); /* actually execute the regular expression */ - if (onig_search(re, (OnigUChar *)string, (OnigUChar *)(string + string_len), (OnigUChar *)string, (OnigUChar *)(string + string_len), regs, 0) < 0) { + if (_php_mb_onig_search(re, (OnigUChar *)string, (OnigUChar *)(string + string_len), (OnigUChar *)string, (OnigUChar *)(string + string_len), regs, 0) < 0) { RETVAL_FALSE; goto out; } @@ -1064,7 +1093,7 @@ static void _php_mb_regex_ereg_replace_exec(INTERNAL_FUNCTION_PARAMETERS, OnigOp string_lim = (OnigUChar*)(string + string_len); regs = onig_region_new(); while (err >= 0) { - err = onig_search(re, (OnigUChar *)string, (OnigUChar *)string_lim, pos, (OnigUChar *)string_lim, regs, 0); + err = _php_mb_onig_search(re, (OnigUChar *)string, (OnigUChar *)string_lim, pos, (OnigUChar *)string_lim, regs, 0); if (err <= -2) { OnigUChar err_str[ONIG_MAX_ERROR_MESSAGE_LEN]; onig_error_code_to_str(err_str, err); @@ -1245,7 +1274,7 @@ PHP_FUNCTION(mb_split) /* churn through str, generating array entries as we go */ while (count != 0 && (size_t)(pos - (OnigUChar *)string) < string_len) { size_t beg, end; - err = onig_search(re, (OnigUChar *)string, (OnigUChar *)(string + string_len), pos, (OnigUChar *)(string + string_len), regs, 0); + err = _php_mb_onig_search(re, (OnigUChar *)string, (OnigUChar *)(string + string_len), pos, (OnigUChar *)(string + string_len), regs, 0); if (err < 0) { break; } @@ -1302,6 +1331,7 @@ PHP_FUNCTION(mb_ereg_match) OnigSyntaxType *syntax; OnigOptionType option = 0; int err; + OnigMatchParam *mp; { char *option_str = NULL; @@ -1330,8 +1360,14 @@ PHP_FUNCTION(mb_ereg_match) RETURN_FALSE; } + mp = onig_new_match_param(); + onig_initialize_match_param(mp); + 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)); + } /* match */ - err = onig_match(re, (OnigUChar *)string, (OnigUChar *)(string + string_len), (OnigUChar *)string, NULL, 0); + err = onig_match_with_param(re, (OnigUChar *)string, (OnigUChar *)(string + string_len), (OnigUChar *)string, NULL, 0, mp); + onig_free_match_param(mp); if (err >= 0) { RETVAL_TRUE; } else { @@ -1394,7 +1430,7 @@ _php_mb_regex_ereg_search_exec(INTERNAL_FUNCTION_PARAMETERS, int mode) } MBREX(search_regs) = onig_region_new(); - err = onig_search(MBREX(search_re), str, str + len, str + pos, str + len, MBREX(search_regs), 0); + err = _php_mb_onig_search(MBREX(search_re), str, str + len, str + pos, str + len, MBREX(search_regs), 0); if (err == ONIG_MISMATCH) { MBREX(search_pos) = len; RETVAL_FALSE; diff --git a/ext/mbstring/tests/mbregex_stack_limit.phpt b/ext/mbstring/tests/mbregex_stack_limit.phpt new file mode 100644 index 0000000000..a678e3b4f7 --- /dev/null +++ b/ext/mbstring/tests/mbregex_stack_limit.phpt @@ -0,0 +1,26 @@ +--TEST-- +Test oniguruma stack limit +--SKIPIF-- +<?php extension_loaded('mbstring') or die('skip mbstring not available'); ?> +--XFAIL-- +Travis CI has old oniguruma library +--FILE-- +<?php +$s = str_repeat(' ', 30000); + +ini_set('mbstring.regex_stack_limit', 10000); +var_dump(mb_ereg('\\s+$', $s)); + +ini_set('mbstring.regex_stack_limit', 30000); +var_dump(mb_ereg('\\s+$', $s)); + +ini_set('mbstring.regex_stack_limit', 30001); +var_dump(mb_ereg('\\s+$', $s)); + +echo 'OK'; +?> +--EXPECT-- +bool(false) +bool(false) +int(1) +OK diff --git a/ext/mbstring/tests/mbregex_stack_limit2.phpt b/ext/mbstring/tests/mbregex_stack_limit2.phpt new file mode 100644 index 0000000000..3ddff10f81 --- /dev/null +++ b/ext/mbstring/tests/mbregex_stack_limit2.phpt @@ -0,0 +1,27 @@ +--TEST-- +Test oniguruma stack limit +--SKIPIF-- +<?php extension_loaded('mbstring') or die('skip mbstring not available'); ?> +--XFAIL-- +Travis CI has old oniguruma library +--FILE-- +<?php +function mb_trim( $string, $chars = "", $chars_array = array() ) +{ + for( $x=0; $x<iconv_strlen( $chars ); $x++ ) $chars_array[] = preg_quote( iconv_substr( $chars, $x, 1 ) ); + $encoded_char_list = implode( "|", array_merge( array( "\s","\t","\n","\r", "\0", "\x0B" ), $chars_array ) ); + + $string = mb_ereg_replace( "^($encoded_char_list)*", "", $string ); + $string = mb_ereg_replace( "($encoded_char_list)*$", "", $string ); + return $string; +} + +ini_set('mbstring.regex_stack_limit', 10000); +var_dump(mb_trim(str_repeat(' ', 10000))); + +echo 'OK'; +?> +--EXPECTF-- +Warning: mb_ereg_replace(): mbregex search failure in php_mbereg_replace_exec(): match-stack limit over in %s on line %d +string(0) "" +OK diff --git a/php.ini-development b/php.ini-development index 0bf89f4543..766e8ec3d3 100644 --- a/php.ini-development +++ b/php.ini-development @@ -1686,6 +1686,11 @@ zend.assertions = 1 ; Default: mbstring.http_output_conv_mimetype=^(text/|application/xhtml\+xml) ;mbstring.http_output_conv_mimetype= +; This directive specifies maximum stack depth for mbstring regular expressions. It is similar +; to the pcre.recursion_limit for PCRE. +; Default: 100000 +;mbstring.regex_stack_limit=100000 + [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 457b93e0b4..cd19bab021 100644 --- a/php.ini-production +++ b/php.ini-production @@ -1686,6 +1686,11 @@ zend.assertions = -1 ; Default: mbstring.http_output_conv_mimetype=^(text/|application/xhtml\+xml) ;mbstring.http_output_conv_mimetype= +; This directive specifies maximum stack depth for mbstring regular expressions. It is similar +; to the pcre.recursion_limit for PCRE. +; Default: 100000 +;mbstring.regex_stack_limit=100000 + [gd] ; Tell the jpeg decode to ignore warnings and try to create ; a gd image. The warning will then be displayed as notices |