|   | php.net | support | documentation | report a bug | advanced search | search howto | statistics | random bug | login | 
| 
 PatchesPull RequestsHistoryAllCommentsChangesGit/SVN commits              [2016-10-27 00:11 UTC] stas@php.net
 
-Type:    Security
+Type:    Bug
-Package: Reproducible crash
+Package: PCRE related
  [2016-10-28 13:22 UTC] laruence@php.net
  [2016-10-28 13:22 UTC] laruence@php.net
 
-Status: Open
+Status: Closed
  [2016-11-09 03:33 UTC] krakjoe@php.net
 | |||||||||||||||||||||||||||
|  Copyright © 2001-2025 The PHP Group All rights reserved. | Last updated: Fri Oct 31 18:00:01 2025 UTC | 
Description: ------------ A possible use-after-free bug in zend allocator. (1)Under the case USE_ZEND_ALLOC = 0 Output by address sanitizer: The following is the dump information: Warning: preg_replace_callback_array(): Delimiter must not be alphanumeric or backslash in /home/dango/Development/Fuzz/PHP7.0.12Fuzz/Analysis/crash03.php on line 18 ================================================================= ==27591==ERROR: AddressSanitizer: heap-use-after-free on address 0xb58484f5 at pc 0x87f122d bp 0xbfdb7f38 sp 0xbfdb7f30 READ of size 1 at 0xb58484f5 thread T0 #0 0x87f122c in php_replace_in_subject (/home/dango/Development/Fuzz/PHP7.0.12Fuzz/php-asan/sapi/cli/php+0x87f122c) 0xb58484f5 is located 5 bytes inside of 20-byte region [0xb58484f0,0xb5848504) freed by thread T0 here: #0 0x80eee31 in __interceptor_free (/home/dango/Development/Fuzz/PHP7.0.12Fuzz/php-asan/sapi/cli/php+0x80eee31) #1 0xad32148 in _efree (/home/dango/Development/Fuzz/PHP7.0.12Fuzz/php-asan/sapi/cli/php+0xad32148) #2 0xafeaedb in _zval_dtor_func_for_ptr (/home/dango/Development/Fuzz/PHP7.0.12Fuzz/php-asan/sapi/cli/php+0xafeaedb) #3 0xaea04c4 in _zval_ptr_dtor (/home/dango/Development/Fuzz/PHP7.0.12Fuzz/php-asan/sapi/cli/php+0xaea04c4) #4 0x87cebfc in zif_preg_replace_callback_array (/home/dango/Development/Fuzz/PHP7.0.12Fuzz/php-asan/sapi/cli/php+0x87cebfc) #5 0xbda1d7e in ZEND_DO_ICALL_SPEC_HANDLER (/home/dango/Development/Fuzz/PHP7.0.12Fuzz/php-asan/sapi/cli/php+0xbda1d7e) #6 0xb66221f in execute_ex (/home/dango/Development/Fuzz/PHP7.0.12Fuzz/php-asan/sapi/cli/php+0xb66221f) #7 0xb6689a4 in zend_execute (/home/dango/Development/Fuzz/PHP7.0.12Fuzz/php-asan/sapi/cli/php+0xb6689a4) #8 0xb012d94 in zend_execute_scripts (/home/dango/Development/Fuzz/PHP7.0.12Fuzz/php-asan/sapi/cli/php+0xb012d94) #9 0xa943801 in php_execute_script (/home/dango/Development/Fuzz/PHP7.0.12Fuzz/php-asan/sapi/cli/php+0xa943801) #10 0xc1b30ee in do_cli (/home/dango/Development/Fuzz/PHP7.0.12Fuzz/php-asan/sapi/cli/php+0xc1b30ee) #11 0xc1aa67f in main (/home/dango/Development/Fuzz/PHP7.0.12Fuzz/php-asan/sapi/cli/php+0xc1aa67f) #12 0xb7388a82 (/lib/i386-linux-gnu/libc.so.6+0x19a82) previously allocated by thread T0 here: #0 0x80eeff1 in malloc (/home/dango/Development/Fuzz/PHP7.0.12Fuzz/php-asan/sapi/cli/php+0x80eeff1) #1 0xad362d6 in __zend_malloc (/home/dango/Development/Fuzz/PHP7.0.12Fuzz/php-asan/sapi/cli/php+0xad362d6) #2 0xad2fcab in _emalloc (/home/dango/Development/Fuzz/PHP7.0.12Fuzz/php-asan/sapi/cli/php+0xad2fcab) #3 0x879f631 in php_pcre_replace_impl (/home/dango/Development/Fuzz/PHP7.0.12Fuzz/php-asan/sapi/cli/php+0x879f631) #4 0x87958ce in php_pcre_replace (/home/dango/Development/Fuzz/PHP7.0.12Fuzz/php-asan/sapi/cli/php+0x87958ce) #5 0x87f523c in php_replace_in_subject (/home/dango/Development/Fuzz/PHP7.0.12Fuzz/php-asan/sapi/cli/php+0x87f523c) #6 0x87efb68 in preg_replace_impl (/home/dango/Development/Fuzz/PHP7.0.12Fuzz/php-asan/sapi/cli/php+0x87efb68) #7 0x87ceb2e in zif_preg_replace_callback_array (/home/dango/Development/Fuzz/PHP7.0.12Fuzz/php-asan/sapi/cli/php+0x87ceb2e) #8 0xbda1d7e in ZEND_DO_ICALL_SPEC_HANDLER (/home/dango/Development/Fuzz/PHP7.0.12Fuzz/php-asan/sapi/cli/php+0xbda1d7e) #9 0xb66221f in execute_ex (/home/dango/Development/Fuzz/PHP7.0.12Fuzz/php-asan/sapi/cli/php+0xb66221f) #10 0xb6689a4 in zend_execute (/home/dango/Development/Fuzz/PHP7.0.12Fuzz/php-asan/sapi/cli/php+0xb6689a4) #11 0xb012d94 in zend_execute_scripts (/home/dango/Development/Fuzz/PHP7.0.12Fuzz/php-asan/sapi/cli/php+0xb012d94) #12 0xa943801 in php_execute_script (/home/dango/Development/Fuzz/PHP7.0.12Fuzz/php-asan/sapi/cli/php+0xa943801) #13 0xc1b30ee in do_cli (/home/dango/Development/Fuzz/PHP7.0.12Fuzz/php-asan/sapi/cli/php+0xc1b30ee) #14 0xc1aa67f in main (/home/dango/Development/Fuzz/PHP7.0.12Fuzz/php-asan/sapi/cli/php+0xc1aa67f) #15 0xb7388a82 (/lib/i386-linux-gnu/libc.so.6+0x19a82) SUMMARY: AddressSanitizer: heap-use-after-free ??:0 php_replace_in_subject Shadow bytes around the buggy address: 0x36b09040: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x36b09050: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x36b09060: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x36b09070: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x36b09080: fd fd fd fa fa fa fd fd fd fd fa fa 00 00 00 01 =>0x36b09090: fa fa fd fd fd fa fa fa fd fd fd fd fa fa[fd]fd 0x36b090a0: fd fa fa fa fd fd fd fd fa fa fd fd fd fa fa fa 0x36b090b0: 00 00 04 fa fa fa fd fd fd fd fa fa fd fd fd fd 0x36b090c0: fa fa fd fd fd fa fa fa fd fd fd fa fa fa 00 00 0x36b090d0: 04 fa fa fa fd fd fd fd fa fa fd fd fd fa fa fa 0x36b090e0: fd fd fd fa fa fa 00 00 04 fa fa fa fd fd fd fd Shadow byte legend (one shadow byte represents 8 application bytes): Addressable: 00 Partially addressable: 01 02 03 04 05 06 07 Heap left redzone: fa Heap right redzone: fb Freed heap region: fd Stack left redzone: f1 Stack mid redzone: f2 Stack right redzone: f3 Stack partial redzone: f4 Stack after return: f5 Stack use after scope: f8 Global redzone: f9 Global init order: f6 Poisoned by user: f7 ASan internal: fe ==27591==ABORTING (2)Under the situation USE_ZEND_ALLOC=1 There is no crash. Compile v7.0.12 with gcc-4.8.4. Run the poc file under gdb, execute the following script: set pagination off set output-radix 16 set logging overwrite on set logging file 01log set logging on break *0x81035be commands p/x $eax x/4x $eax end ignore 1 3 run < poc.php Observe at the breakpoint as following: Breakpoint 1, 0x081035be in zend_string_copy (s=0xb7a5c5e8) at /home/dango/Development/Fuzz/PHP7.0.12Fuzz/php-7.0.12/Zend/zend_string.h:167 167 GC_REFCOUNT(s)++; $1 = 0xb7a5c5e8 0xb7a5c5e8: 0xb7a5c750 0x00000006 0x8b887389 0x00000003 (gdb) x/4i $eip => 0x81035be <php_replace_in_subject+61>: mov (%eax),%eax 0x81035c0 <php_replace_in_subject+63>: lea 0x1(%eax),%edx 0x81035c3 <php_replace_in_subject+66>: mov -0x6c(%ebp),%eax 0x81035c6 <php_replace_in_subject+69>: mov %edx,(%eax) The 0xb7a5c5e8 is now in the free list, but there still exists a reference to it by zend_string_copy. At 0x81035c0, the reference counter will be increased by one, which clearly shows that there still exists use-after-free bug here. There is another interesting fact. I call a1=>array("Foo", "rep") in poc file is an unexpected line. If we set a watch point on 0xb7a5c5e8 and add more unexpected lines in the poc file, the value at 0xb7a5c5e8 will be subtracted by one. The times of subtraction is decided by the how many unexpected lines are added. I think there exist a way to control the return value of zend_mm_alloc_small. Test script: --------------- <?php class Rep { public function __invoke() { return "d"; } } class Foo { public static function rep($rep) { return "ok"; } } function b() { return "b"; } var_dump(preg_replace_callback_array( array( "/a/" => 'b', "/b/" => function () { return "c"; }, "/c/" => new Rep, reporting=> array("Foo", "rep"), a1=>array("Foo", "rep"), ), 'a')); ?>