summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStanislav Malyshev <stas@php.net>2019-04-01 00:05:36 -0700
committerStanislav Malyshev <stas@php.net>2019-04-01 00:05:36 -0700
commit077ce33aa98d3c428c968091002cdbd559a8fc58 (patch)
treecb385eb3dba3bc71beb5c942bf9b9732e2a3a7cc
parent9dcf95ab76fb01ea905369efec0ea2ac54ffade7 (diff)
parent3d5b6f234e3172b193856aec23fd3f6cf14e464b (diff)
downloadphp-git-077ce33aa98d3c428c968091002cdbd559a8fc58.tar.gz
Merge branch 'PHP-7.3' into PHP-7.4
* PHP-7.3: 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.c29
-rw-r--r--ext/mbstring/mbstring.h1
-rw-r--r--ext/mbstring/php_mbregex.c46
-rw-r--r--ext/mbstring/tests/mbregex_stack_limit.phpt24
-rw-r--r--ext/mbstring/tests/mbregex_stack_limit2.phpt25
-rw-r--r--php.ini-development5
-rw-r--r--php.ini-production5
7 files changed, 127 insertions, 8 deletions
diff --git a/ext/mbstring/mbstring.c b/ext/mbstring/mbstring.c
index cf0b08be6e..d8248aac5d 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
@@ -1031,9 +1042,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;
}
/* }}} */
@@ -1506,6 +1526,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 7321525064..cd882c1c03 100644
--- a/ext/mbstring/mbstring.h
+++ b/ext/mbstring/mbstring.h
@@ -165,6 +165,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 5128fabc34..12ee4cf47c 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)
{
@@ -914,7 +943,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;
}
@@ -1095,7 +1124,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);
@@ -1276,7 +1305,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;
}
@@ -1333,6 +1362,7 @@ PHP_FUNCTION(mb_ereg_match)
OnigSyntaxType *syntax;
OnigOptionType option = 0;
int err;
+ OnigMatchParam *mp;
{
char *option_str = NULL;
@@ -1361,8 +1391,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 {
@@ -1425,7 +1461,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..9d0f3acc9d
--- /dev/null
+++ b/ext/mbstring/tests/mbregex_stack_limit.phpt
@@ -0,0 +1,24 @@
+--TEST--
+Test oniguruma stack limit
+--SKIPIF--
+<?php extension_loaded('mbstring') or die('skip mbstring not available'); ?>
+--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..12c8c8edab
--- /dev/null
+++ b/ext/mbstring/tests/mbregex_stack_limit2.phpt
@@ -0,0 +1,25 @@
+--TEST--
+Test oniguruma stack limit
+--SKIPIF--
+<?php extension_loaded('mbstring') or die('skip mbstring not available'); ?>
+--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 a058c0495c..138ed5e542 100644
--- a/php.ini-development
+++ b/php.ini-development
@@ -1712,6 +1712,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 9c4091b578..4125de2a1d 100644
--- a/php.ini-production
+++ b/php.ini-production
@@ -1719,6 +1719,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