Skip to content

Commit 8b3c1a3

Browse files
committed
fix bug #55856: preg_replace should fail on trailing garbage
1 parent f82dd2c commit 8b3c1a3

File tree

3 files changed

+66
-12
lines changed

3 files changed

+66
-12
lines changed

NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ PHP NEWS
3939
- Installation:
4040
. Fixed bug #62460 (php binaries installed as binary.dSYM). (Reeze Xia)
4141

42+
- PCRE:
43+
. Fixed bug #55856 (preg_replace should fail on trailing garbage).
44+
(reg dot php at alf dot nu)
45+
4246
- PDO:
4347
. Fixed bug #62685 (Wrong return datatype in PDO::inTransaction()). (Laruence)
4448

ext/pcre/php_pcre.c

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,8 @@ PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache(char *regex, int regex_le
275275
get to the end without encountering a delimiter. */
276276
while (isspace((int)*(unsigned char *)p)) p++;
277277
if (*p == 0) {
278-
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Empty regular expression");
278+
php_error_docref(NULL TSRMLS_CC, E_WARNING,
279+
p < regex + regex_len ? "Null byte in regex" : "Empty regular expression");
279280
return NULL;
280281
}
281282

@@ -292,29 +293,25 @@ PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache(char *regex, int regex_le
292293
delimiter = pp[5];
293294
end_delimiter = delimiter;
294295

296+
pp = p;
297+
295298
if (start_delimiter == end_delimiter) {
296299
/* We need to iterate through the pattern, searching for the ending delimiter,
297300
but skipping the backslashed delimiters. If the ending delimiter is not
298301
found, display a warning. */
299-
pp = p;
300302
while (*pp != 0) {
301303
if (*pp == '\\' && pp[1] != 0) pp++;
302304
else if (*pp == delimiter)
303305
break;
304306
pp++;
305307
}
306-
if (*pp == 0) {
307-
php_error_docref(NULL TSRMLS_CC,E_WARNING, "No ending delimiter '%c' found", delimiter);
308-
return NULL;
309-
}
310308
} else {
311309
/* We iterate through the pattern, searching for the matching ending
312310
* delimiter. For each matching starting delimiter, we increment nesting
313311
* level, and decrement it for each matching ending delimiter. If we
314312
* reach the end of the pattern without matching, display a warning.
315313
*/
316314
int brackets = 1; /* brackets nesting level */
317-
pp = p;
318315
while (*pp != 0) {
319316
if (*pp == '\\' && pp[1] != 0) pp++;
320317
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
323320
brackets++;
324321
pp++;
325322
}
326-
if (*pp == 0) {
327-
php_error_docref(NULL TSRMLS_CC,E_WARNING, "No ending matching delimiter '%c' found", end_delimiter);
328-
return NULL;
323+
}
324+
325+
if (*pp == 0) {
326+
if (pp < regex + regex_len) {
327+
php_error_docref(NULL TSRMLS_CC,E_WARNING, "Null byte in regex");
328+
} else if (start_delimiter == end_delimiter) {
329+
php_error_docref(NULL TSRMLS_CC,E_WARNING, "No ending delimiter '%c' found", delimiter);
330+
} else {
331+
php_error_docref(NULL TSRMLS_CC,E_WARNING, "No ending matching delimiter '%c' found", delimiter);
329332
}
333+
return NULL;
330334
}
331335

332336
/* 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
337341

338342
/* Parse through the options, setting appropriate flags. Display
339343
a warning if we encounter an unknown modifier. */
340-
while (*pp != 0) {
344+
while (pp < regex + regex_len) {
341345
switch (*pp++) {
342346
/* Perl compatible options */
343347
case 'i': coptions |= PCRE_CASELESS; break;
@@ -368,7 +372,11 @@ PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache(char *regex, int regex_le
368372
break;
369373

370374
default:
371-
php_error_docref(NULL TSRMLS_CC,E_WARNING, "Unknown modifier '%c'", pp[-1]);
375+
if (pp[-1]) {
376+
php_error_docref(NULL TSRMLS_CC,E_WARNING, "Unknown modifier '%c'", pp[-1]);
377+
} else {
378+
php_error_docref(NULL TSRMLS_CC,E_WARNING, "Null byte in regex");
379+
}
372380
efree(pattern);
373381
return NULL;
374382
}

ext/pcre/tests/null_bytes.phpt

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
--TEST--
2+
Zero byte test
3+
--FILE--
4+
<?php
5+
6+
preg_match("\0//i", "");
7+
preg_match("/\0/i", "");
8+
preg_match("//\0i", "");
9+
preg_match("//i\0", "");
10+
preg_match("/\\\0/i", "");
11+
12+
preg_match("\0[]i", "");
13+
preg_match("[\0]i", "");
14+
preg_match("[]\0i", "");
15+
preg_match("[]i\0", "");
16+
preg_match("[\\\0]i", "");
17+
18+
preg_replace("/foo/e\0/i", "echo('Eek');", "");
19+
20+
?>
21+
--EXPECTF--
22+
Warning: preg_match(): Null byte in regex in %snull_bytes.php on line 3
23+
24+
Warning: preg_match(): Null byte in regex in %snull_bytes.php on line 4
25+
26+
Warning: preg_match(): Null byte in regex in %snull_bytes.php on line 5
27+
28+
Warning: preg_match(): Null byte in regex in %snull_bytes.php on line 6
29+
30+
Warning: preg_match(): Null byte in regex in %snull_bytes.php on line 7
31+
32+
Warning: preg_match(): Null byte in regex in %snull_bytes.php on line 9
33+
34+
Warning: preg_match(): Null byte in regex in %snull_bytes.php on line 10
35+
36+
Warning: preg_match(): Null byte in regex in %snull_bytes.php on line 11
37+
38+
Warning: preg_match(): Null byte in regex in %snull_bytes.php on line 12
39+
40+
Warning: preg_match(): Null byte in regex in %snull_bytes.php on line 13
41+
42+
Warning: preg_replace(): Null byte in regex in %snull_bytes.php on line 15

0 commit comments

Comments
 (0)