Skip to content

Commit 077ce33

Browse files
committed
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.
2 parents 9dcf95a + 3d5b6f2 commit 077ce33

File tree

7 files changed

+127
-8
lines changed

7 files changed

+127
-8
lines changed

ext/mbstring/mbstring.c

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,17 @@
6060
# include "php_onig_compat.h"
6161
# include <oniguruma.h>
6262
# undef UChar
63+
#if ONIGURUMA_VERSION_INT < 60800
64+
typedef void OnigMatchParam;
65+
#define onig_new_match_param() (NULL)
66+
#define onig_initialize_match_param(x)
67+
#define onig_set_match_stack_limit_size_of_match_param(x, y)
68+
#define onig_free_match_param(x)
69+
#define onig_search_with_param(reg, str, end, start, range, region, option, mp) \
70+
onig_search(reg, str, end, start, range, region, option)
71+
#define onig_match_with_param(re, str, end, at, region, option, mp) \
72+
onig_match(re, str, end, at, region, option)
73+
#endif
6374
#else
6475
# include "ext/pcre/php_pcre.h"
6576
#endif
@@ -1031,9 +1042,18 @@ static void *_php_mb_compile_regex(const char *pattern)
10311042
/* {{{ _php_mb_match_regex */
10321043
static int _php_mb_match_regex(void *opaque, const char *str, size_t str_len)
10331044
{
1034-
return onig_search((php_mb_regex_t *)opaque, (const OnigUChar *)str,
1035-
(const OnigUChar*)str + str_len, (const OnigUChar *)str,
1036-
(const OnigUChar*)str + str_len, NULL, ONIG_OPTION_NONE) >= 0;
1045+
OnigMatchParam *mp = onig_new_match_param();
1046+
int err;
1047+
onig_initialize_match_param(mp);
1048+
if (!ZEND_LONG_UINT_OVFL(MBSTRG(regex_stack_limit))) {
1049+
onig_set_match_stack_limit_size_of_match_param(mp, (unsigned int)MBSTRG(regex_stack_limit));
1050+
}
1051+
/* search */
1052+
err = onig_search_with_param((php_mb_regex_t *)opaque, (const OnigUChar *)str,
1053+
(const OnigUChar*)str + str_len, (const OnigUChar *)str,
1054+
(const OnigUChar*)str + str_len, NULL, ONIG_OPTION_NONE, mp);
1055+
onig_free_match_param(mp);
1056+
return err >= 0;
10371057
}
10381058
/* }}} */
10391059

@@ -1506,6 +1526,9 @@ PHP_INI_BEGIN()
15061526
PHP_INI_ALL,
15071527
OnUpdateBool,
15081528
strict_detection, zend_mbstring_globals, mbstring_globals)
1529+
#if HAVE_MBREGEX
1530+
STD_PHP_INI_ENTRY("mbstring.regex_stack_limit", "100000",PHP_INI_ALL, OnUpdateLong, regex_stack_limit, zend_mbstring_globals, mbstring_globals)
1531+
#endif
15091532
PHP_INI_END()
15101533
/* }}} */
15111534

ext/mbstring/mbstring.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@ ZEND_BEGIN_MODULE_GLOBALS(mbstring)
165165
void *http_output_conv_mimetypes;
166166
#if HAVE_MBREGEX
167167
struct _zend_mb_regex_globals *mb_regex_globals;
168+
zend_long regex_stack_limit;
168169
#endif
169170
zend_string *last_used_encoding_name;
170171
const mbfl_encoding *last_used_encoding;

ext/mbstring/php_mbregex.c

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,18 @@
3434
#include <oniguruma.h>
3535
#undef UChar
3636

37+
#if ONIGURUMA_VERSION_INT < 60800
38+
typedef void OnigMatchParam;
39+
#define onig_new_match_param() (NULL)
40+
#define onig_initialize_match_param(x)
41+
#define onig_set_match_stack_limit_size_of_match_param(x, y)
42+
#define onig_free_match_param(x)
43+
#define onig_search_with_param(reg, str, end, start, range, region, option, mp) \
44+
onig_search(reg, str, end, start, range, region, option)
45+
#define onig_match_with_param(re, str, end, at, region, option, mp) \
46+
onig_match(re, str, end, at, region, option)
47+
#endif
48+
3749
ZEND_EXTERN_MODULE_GLOBALS(mbstring)
3850

3951
struct _zend_mb_regex_globals {
@@ -853,6 +865,23 @@ PHP_FUNCTION(mb_regex_encoding)
853865
}
854866
/* }}} */
855867

868+
/* {{{ _php_mb_onig_search */
869+
static int _php_mb_onig_search(regex_t* reg, const OnigUChar* str, const OnigUChar* end, const OnigUChar* start,
870+
const OnigUChar* range, OnigRegion* region, OnigOptionType option) {
871+
OnigMatchParam *mp = onig_new_match_param();
872+
int err;
873+
onig_initialize_match_param(mp);
874+
if (!ZEND_LONG_UINT_OVFL(MBSTRG(regex_stack_limit))) {
875+
onig_set_match_stack_limit_size_of_match_param(mp, (unsigned int)MBSTRG(regex_stack_limit));
876+
}
877+
/* search */
878+
err = onig_search_with_param(reg, str, end, start, range, region, option, mp);
879+
onig_free_match_param(mp);
880+
return err;
881+
}
882+
/* }}} */
883+
884+
856885
/* {{{ _php_mb_regex_ereg_exec */
857886
static void _php_mb_regex_ereg_exec(INTERNAL_FUNCTION_PARAMETERS, int icase)
858887
{
@@ -914,7 +943,7 @@ static void _php_mb_regex_ereg_exec(INTERNAL_FUNCTION_PARAMETERS, int icase)
914943
regs = onig_region_new();
915944

916945
/* actually execute the regular expression */
917-
if (onig_search(re, (OnigUChar *)string, (OnigUChar *)(string + string_len), (OnigUChar *)string, (OnigUChar *)(string + string_len), regs, 0) < 0) {
946+
if (_php_mb_onig_search(re, (OnigUChar *)string, (OnigUChar *)(string + string_len), (OnigUChar *)string, (OnigUChar *)(string + string_len), regs, 0) < 0) {
918947
RETVAL_FALSE;
919948
goto out;
920949
}
@@ -1095,7 +1124,7 @@ static void _php_mb_regex_ereg_replace_exec(INTERNAL_FUNCTION_PARAMETERS, OnigOp
10951124
string_lim = (OnigUChar*)(string + string_len);
10961125
regs = onig_region_new();
10971126
while (err >= 0) {
1098-
err = onig_search(re, (OnigUChar *)string, (OnigUChar *)string_lim, pos, (OnigUChar *)string_lim, regs, 0);
1127+
err = _php_mb_onig_search(re, (OnigUChar *)string, (OnigUChar *)string_lim, pos, (OnigUChar *)string_lim, regs, 0);
10991128
if (err <= -2) {
11001129
OnigUChar err_str[ONIG_MAX_ERROR_MESSAGE_LEN];
11011130
onig_error_code_to_str(err_str, err);
@@ -1276,7 +1305,7 @@ PHP_FUNCTION(mb_split)
12761305
/* churn through str, generating array entries as we go */
12771306
while (count != 0 && (size_t)(pos - (OnigUChar *)string) < string_len) {
12781307
size_t beg, end;
1279-
err = onig_search(re, (OnigUChar *)string, (OnigUChar *)(string + string_len), pos, (OnigUChar *)(string + string_len), regs, 0);
1308+
err = _php_mb_onig_search(re, (OnigUChar *)string, (OnigUChar *)(string + string_len), pos, (OnigUChar *)(string + string_len), regs, 0);
12801309
if (err < 0) {
12811310
break;
12821311
}
@@ -1333,6 +1362,7 @@ PHP_FUNCTION(mb_ereg_match)
13331362
OnigSyntaxType *syntax;
13341363
OnigOptionType option = 0;
13351364
int err;
1365+
OnigMatchParam *mp;
13361366

13371367
{
13381368
char *option_str = NULL;
@@ -1361,8 +1391,14 @@ PHP_FUNCTION(mb_ereg_match)
13611391
RETURN_FALSE;
13621392
}
13631393

1394+
mp = onig_new_match_param();
1395+
onig_initialize_match_param(mp);
1396+
if(MBSTRG(regex_stack_limit) > 0 && MBSTRG(regex_stack_limit) < UINT_MAX) {
1397+
onig_set_match_stack_limit_size_of_match_param(mp, (unsigned int)MBSTRG(regex_stack_limit));
1398+
}
13641399
/* match */
1365-
err = onig_match(re, (OnigUChar *)string, (OnigUChar *)(string + string_len), (OnigUChar *)string, NULL, 0);
1400+
err = onig_match_with_param(re, (OnigUChar *)string, (OnigUChar *)(string + string_len), (OnigUChar *)string, NULL, 0, mp);
1401+
onig_free_match_param(mp);
13661402
if (err >= 0) {
13671403
RETVAL_TRUE;
13681404
} else {
@@ -1425,7 +1461,7 @@ _php_mb_regex_ereg_search_exec(INTERNAL_FUNCTION_PARAMETERS, int mode)
14251461
}
14261462
MBREX(search_regs) = onig_region_new();
14271463

1428-
err = onig_search(MBREX(search_re), str, str + len, str + pos, str + len, MBREX(search_regs), 0);
1464+
err = _php_mb_onig_search(MBREX(search_re), str, str + len, str + pos, str + len, MBREX(search_regs), 0);
14291465
if (err == ONIG_MISMATCH) {
14301466
MBREX(search_pos) = len;
14311467
RETVAL_FALSE;
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
--TEST--
2+
Test oniguruma stack limit
3+
--SKIPIF--
4+
<?php extension_loaded('mbstring') or die('skip mbstring not available'); ?>
5+
--FILE--
6+
<?php
7+
$s = str_repeat(' ', 30000);
8+
9+
ini_set('mbstring.regex_stack_limit', 10000);
10+
var_dump(mb_ereg('\\s+$', $s));
11+
12+
ini_set('mbstring.regex_stack_limit', 30000);
13+
var_dump(mb_ereg('\\s+$', $s));
14+
15+
ini_set('mbstring.regex_stack_limit', 30001);
16+
var_dump(mb_ereg('\\s+$', $s));
17+
18+
echo 'OK';
19+
?>
20+
--EXPECT--
21+
bool(false)
22+
bool(false)
23+
int(1)
24+
OK
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
--TEST--
2+
Test oniguruma stack limit
3+
--SKIPIF--
4+
<?php extension_loaded('mbstring') or die('skip mbstring not available'); ?>
5+
--FILE--
6+
<?php
7+
function mb_trim( $string, $chars = "", $chars_array = array() )
8+
{
9+
for( $x=0; $x<iconv_strlen( $chars ); $x++ ) $chars_array[] = preg_quote( iconv_substr( $chars, $x, 1 ) );
10+
$encoded_char_list = implode( "|", array_merge( array( "\s","\t","\n","\r", "\0", "\x0B" ), $chars_array ) );
11+
12+
$string = mb_ereg_replace( "^($encoded_char_list)*", "", $string );
13+
$string = mb_ereg_replace( "($encoded_char_list)*$", "", $string );
14+
return $string;
15+
}
16+
17+
ini_set('mbstring.regex_stack_limit', 10000);
18+
var_dump(mb_trim(str_repeat(' ', 10000)));
19+
20+
echo 'OK';
21+
?>
22+
--EXPECTF--
23+
Warning: mb_ereg_replace(): mbregex search failure in php_mbereg_replace_exec(): match-stack limit over in %s on line %d
24+
string(0) ""
25+
OK

php.ini-development

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1712,6 +1712,11 @@ zend.assertions = 1
17121712
; Default: mbstring.http_output_conv_mimetype=^(text/|application/xhtml\+xml)
17131713
;mbstring.http_output_conv_mimetype=
17141714

1715+
; This directive specifies maximum stack depth for mbstring regular expressions. It is similar
1716+
; to the pcre.recursion_limit for PCRE.
1717+
; Default: 100000
1718+
;mbstring.regex_stack_limit=100000
1719+
17151720
[gd]
17161721
; Tell the jpeg decode to ignore warnings and try to create
17171722
; a gd image. The warning will then be displayed as notices

php.ini-production

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1719,6 +1719,11 @@ zend.assertions = -1
17191719
; Default: mbstring.http_output_conv_mimetype=^(text/|application/xhtml\+xml)
17201720
;mbstring.http_output_conv_mimetype=
17211721

1722+
; This directive specifies maximum stack depth for mbstring regular expressions. It is similar
1723+
; to the pcre.recursion_limit for PCRE.
1724+
; Default: 100000
1725+
;mbstring.regex_stack_limit=100000
1726+
17221727
[gd]
17231728
; Tell the jpeg decode to ignore warnings and try to create
17241729
; a gd image. The warning will then be displayed as notices

0 commit comments

Comments
 (0)