Skip to content

Commit c4bb075

Browse files
committed
Fix GH-16184: UBSan address overflowed in ext/pcre/php_pcre.c
libpcre2 can return the special value -1 for a non-match. In this case we get pointer overflow, although it doesn't matter in practice because the pointer will be in bounds and the copy length will be 0. Still, we should fix the UBSAN warning. Closes GH-16205.
1 parent f453d1a commit c4bb075

File tree

3 files changed

+21
-4
lines changed

3 files changed

+21
-4
lines changed

NEWS

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,9 @@ PHP NEWS
3838
. Fixed stub for openssl_csr_new. (Jakub Zelenka)
3939

4040
- PCRE:
41-
. Fixed GH-16189 (underflow on offset argument). (David Carlier)
41+
. Fixed bug GH-16189 (underflow on offset argument). (David Carlier)
42+
. Fixed bug GH-16184 (UBSan address overflowed in ext/pcre/php_pcre.c).
43+
(nielsdos)
4244

4345
- PHPDBG:
4446
. Fixed bug GH-15901 (phpdbg: Assertion failure on i funcs). (cmb)

ext/pcre/php_pcre.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1747,9 +1747,11 @@ PHPAPI zend_string *php_pcre_replace_impl(pcre_cache_entry *pce, zend_string *su
17471747
}
17481748
if (preg_get_backref(&walk, &backref)) {
17491749
if (backref < count) {
1750-
match_len = offsets[(backref<<1)+1] - offsets[backref<<1];
1751-
memcpy(walkbuf, subject + offsets[backref<<1], match_len);
1752-
walkbuf += match_len;
1750+
if (offsets[backref<<1] < SIZE_MAX) {
1751+
match_len = offsets[(backref<<1)+1] - offsets[backref<<1];
1752+
memcpy(walkbuf, subject + offsets[backref<<1], match_len);
1753+
walkbuf += match_len;
1754+
}
17531755
}
17541756
continue;
17551757
}

ext/pcre/tests/gh16184.phpt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
--TEST--
2+
GH-16184 (UBSan address overflowed in ext/pcre/php_pcre.c)
3+
--CREDITS--
4+
YuanchengJiang
5+
--FILE--
6+
<?php
7+
8+
$string = 'This is a string. It contains numbers (0*9) as well as parentheses and some other things!';
9+
echo preg_replace(array('/\b\w{1}s/', '/(\d{1})*(\d{1})/', '/[\(!\)]/'), array('test', '$1 to $2', '*'), $string), "\n";
10+
11+
?>
12+
--EXPECT--
13+
This test a string. It contains numbers * to 0* to 9* test well test parentheses and some other things*

0 commit comments

Comments
 (0)