php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #73392 A use-after-free in zend allocator management
Submitted: 2016-10-26 14:08 UTC Modified: 2016-10-27 00:11 UTC
From: dangokyo at gmail dot com Assigned:
Status: Closed Package: PCRE related
PHP Version: 7.0.12 OS: Ubuntu14.04
Private report: No CVE-ID:
 [2016-10-26 14:08 UTC] dangokyo at gmail dot com
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'));
?>


Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [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
Automatic comment on behalf of laruence@gmail.com
Revision: http://git.php.net/?p=php-src.git;a=commit;h=e5aa3651470e5f741b16d4f3cd55b7ae6ac5d23a
Log: Fixed bug #73392 (A use-after-free in zend allocator management)
 [2016-10-28 13:22 UTC] laruence@php.net
-Status: Open +Status: Closed
 [2016-11-09 03:33 UTC] krakjoe@php.net
Automatic comment on behalf of laruence@gmail.com
Revision: http://git.php.net/?p=php-src.git;a=commit;h=e5aa3651470e5f741b16d4f3cd55b7ae6ac5d23a
Log: Fixed bug #73392 (A use-after-free in zend allocator management)
 
PHP Copyright © 2001-2017 The PHP Group
All rights reserved.
Last updated: Sat May 27 02:01:36 2017 UTC