fix bug #55856: preg_replace should fail on trailing garbage

This commit is contained in:
Stanislav Malyshev 2012-06-30 16:31:26 -07:00
parent f82dd2c774
commit 8b3c1a380a
3 changed files with 66 additions and 12 deletions

4
NEWS
View file

@ -39,6 +39,10 @@ PHP NEWS
- Installation: - Installation:
. Fixed bug #62460 (php binaries installed as binary.dSYM). (Reeze Xia) . Fixed bug #62460 (php binaries installed as binary.dSYM). (Reeze Xia)
- PCRE:
. Fixed bug #55856 (preg_replace should fail on trailing garbage).
(reg dot php at alf dot nu)
- PDO: - PDO:
. Fixed bug #62685 (Wrong return datatype in PDO::inTransaction()). (Laruence) . Fixed bug #62685 (Wrong return datatype in PDO::inTransaction()). (Laruence)

View file

@ -275,7 +275,8 @@ PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache(char *regex, int regex_le
get to the end without encountering a delimiter. */ get to the end without encountering a delimiter. */
while (isspace((int)*(unsigned char *)p)) p++; while (isspace((int)*(unsigned char *)p)) p++;
if (*p == 0) { if (*p == 0) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Empty regular expression"); php_error_docref(NULL TSRMLS_CC, E_WARNING,
p < regex + regex_len ? "Null byte in regex" : "Empty regular expression");
return NULL; return NULL;
} }
@ -292,21 +293,18 @@ PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache(char *regex, int regex_le
delimiter = pp[5]; delimiter = pp[5];
end_delimiter = delimiter; end_delimiter = delimiter;
pp = p;
if (start_delimiter == end_delimiter) { if (start_delimiter == end_delimiter) {
/* We need to iterate through the pattern, searching for the ending delimiter, /* We need to iterate through the pattern, searching for the ending delimiter,
but skipping the backslashed delimiters. If the ending delimiter is not but skipping the backslashed delimiters. If the ending delimiter is not
found, display a warning. */ found, display a warning. */
pp = p;
while (*pp != 0) { while (*pp != 0) {
if (*pp == '\\' && pp[1] != 0) pp++; if (*pp == '\\' && pp[1] != 0) pp++;
else if (*pp == delimiter) else if (*pp == delimiter)
break; break;
pp++; pp++;
} }
if (*pp == 0) {
php_error_docref(NULL TSRMLS_CC,E_WARNING, "No ending delimiter '%c' found", delimiter);
return NULL;
}
} else { } else {
/* We iterate through the pattern, searching for the matching ending /* We iterate through the pattern, searching for the matching ending
* delimiter. For each matching starting delimiter, we increment nesting * delimiter. For each matching starting delimiter, we increment nesting
@ -314,7 +312,6 @@ PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache(char *regex, int regex_le
* reach the end of the pattern without matching, display a warning. * reach the end of the pattern without matching, display a warning.
*/ */
int brackets = 1; /* brackets nesting level */ int brackets = 1; /* brackets nesting level */
pp = p;
while (*pp != 0) { while (*pp != 0) {
if (*pp == '\\' && pp[1] != 0) pp++; if (*pp == '\\' && pp[1] != 0) pp++;
else if (*pp == end_delimiter && --brackets <= 0) else if (*pp == end_delimiter && --brackets <= 0)
@ -323,10 +320,17 @@ PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache(char *regex, int regex_le
brackets++; brackets++;
pp++; pp++;
} }
if (*pp == 0) { }
php_error_docref(NULL TSRMLS_CC,E_WARNING, "No ending matching delimiter '%c' found", end_delimiter);
return NULL; if (*pp == 0) {
if (pp < regex + regex_len) {
php_error_docref(NULL TSRMLS_CC,E_WARNING, "Null byte in regex");
} else if (start_delimiter == end_delimiter) {
php_error_docref(NULL TSRMLS_CC,E_WARNING, "No ending delimiter '%c' found", delimiter);
} else {
php_error_docref(NULL TSRMLS_CC,E_WARNING, "No ending matching delimiter '%c' found", delimiter);
} }
return NULL;
} }
/* Make a copy of the actual pattern. */ /* Make a copy of the actual pattern. */
@ -337,7 +341,7 @@ PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache(char *regex, int regex_le
/* Parse through the options, setting appropriate flags. Display /* Parse through the options, setting appropriate flags. Display
a warning if we encounter an unknown modifier. */ a warning if we encounter an unknown modifier. */
while (*pp != 0) { while (pp < regex + regex_len) {
switch (*pp++) { switch (*pp++) {
/* Perl compatible options */ /* Perl compatible options */
case 'i': coptions |= PCRE_CASELESS; break; case 'i': coptions |= PCRE_CASELESS; break;
@ -368,7 +372,11 @@ PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache(char *regex, int regex_le
break; break;
default: default:
php_error_docref(NULL TSRMLS_CC,E_WARNING, "Unknown modifier '%c'", pp[-1]); if (pp[-1]) {
php_error_docref(NULL TSRMLS_CC,E_WARNING, "Unknown modifier '%c'", pp[-1]);
} else {
php_error_docref(NULL TSRMLS_CC,E_WARNING, "Null byte in regex");
}
efree(pattern); efree(pattern);
return NULL; return NULL;
} }

View file

@ -0,0 +1,42 @@
--TEST--
Zero byte test
--FILE--
<?php
preg_match("\0//i", "");
preg_match("/\0/i", "");
preg_match("//\0i", "");
preg_match("//i\0", "");
preg_match("/\\\0/i", "");
preg_match("\0[]i", "");
preg_match("[\0]i", "");
preg_match("[]\0i", "");
preg_match("[]i\0", "");
preg_match("[\\\0]i", "");
preg_replace("/foo/e\0/i", "echo('Eek');", "");
?>
--EXPECTF--
Warning: preg_match(): Null byte in regex in %snull_bytes.php on line 3
Warning: preg_match(): Null byte in regex in %snull_bytes.php on line 4
Warning: preg_match(): Null byte in regex in %snull_bytes.php on line 5
Warning: preg_match(): Null byte in regex in %snull_bytes.php on line 6
Warning: preg_match(): Null byte in regex in %snull_bytes.php on line 7
Warning: preg_match(): Null byte in regex in %snull_bytes.php on line 9
Warning: preg_match(): Null byte in regex in %snull_bytes.php on line 10
Warning: preg_match(): Null byte in regex in %snull_bytes.php on line 11
Warning: preg_match(): Null byte in regex in %snull_bytes.php on line 12
Warning: preg_match(): Null byte in regex in %snull_bytes.php on line 13
Warning: preg_replace(): Null byte in regex in %snull_bytes.php on line 15