php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #80894 GC-related crash after using __debugInfo()
Submitted: 2021-03-22 11:28 UTC Modified: 2021-03-24 17:55 UTC
From: tstarling@php.net Assigned: stas (profile)
Status: Wont fix Package: Reproducible crash
PHP Version: 7.3Git-2021-03-22 (Git) OS: Linux
Private report: No CVE-ID: None
 [2021-03-22 11:28 UTC] tstarling@php.net
Description:
------------
While investigating a reproducible segfault encountered in automated testing of https://gerrit.wikimedia.org/r/c/mediawiki/core/+/672845 , I discovered that PHP 7.3's var_dump() does not correctly free the return value of the __debugInfo() method. It uses zend_hash_destroy() instead of zend_array_destroy(), causing the array to potentially remain in the GC root buffer. When the GC runs, the array is freed a second time.

Compiling with AddressSanitizer helped to isolate the issue, allowing it to be demonstrated with a short test case.

PHP 7.4+ is not affected due to the introduction of zend_get_properties_for().

Test script:
---------------
<?php

class C {
	public function __debugInfo() {
		// Clone the empty array and add it to the GC buffer
		$res = array_merge( [] );
		return $res;
	}
}
$c = new C;
var_dump( $c );


Expected result:
----------------
object(C)#1 (0) {
}


Actual result:
--------------
object(C)#1 (0) {
}
=================================================================
==914259==ERROR: AddressSanitizer: heap-use-after-free on address 0x6060000166a4 at pc 0x555556a46f9b bp 0x7fffffffac50 sp 0x7fffffffac40
READ of size 4 at 0x6060000166a4 thread T0
    #0 0x555556a46f9a in gc_mark_roots /srv/php/core/Zend/zend_gc.c:976
    #1 0x555556a4a928 in zend_gc_collect_cycles /srv/php/core/Zend/zend_gc.c:1473
    #2 0x55555697aba2 in shutdown_executor /srv/php/core/Zend/zend_execute_API.c:293
    #3 0x5555569b8c44 in zend_deactivate /srv/php/core/Zend/zend.c:1104
    #4 0x55555685dfcd in php_request_shutdown /srv/php/core/main/main.c:1928
    #5 0x555556c20146 in do_cli /srv/php/core/sapi/cli/php_cli.c:1167
    #6 0x555556c2116e in main /srv/php/core/sapi/cli/php_cli.c:1396
    #7 0x7ffff653d0b2 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x270b2)
    #8 0x555555a6f46d in _start (/srv/php/core/sapi/cli/php+0x51b46d)

0x6060000166a4 is located 4 bytes inside of 56-byte region [0x6060000166a0,0x6060000166d8)
freed by thread T0 here:
    #0 0x7ffff769a7cf in __interceptor_free (/usr/lib/x86_64-linux-gnu/libasan.so.5+0x10d7cf)
    #1 0x55555692d553 in _efree /srv/php/core/Zend/zend_alloc.c:2516
    #2 0x55555666d81a in php_var_dump /srv/php/core/ext/standard/var.c:168
    #3 0x55555666dd5c in zif_var_dump /srv/php/core/ext/standard/var.c:210
    #4 0x555556abb16e in ZEND_DO_ICALL_SPEC_RETVAL_UNUSED_HANDLER /srv/php/core/Zend/zend_vm_execute.h:649
    #5 0x555556c06809 in execute_ex /srv/php/core/Zend/zend_vm_execute.h:55499
    #6 0x555556c17f26 in zend_execute /srv/php/core/Zend/zend_vm_execute.h:60935
    #7 0x5555569bc397 in zend_execute_scripts /srv/php/core/Zend/zend.c:1568
    #8 0x5555568611b2 in php_execute_script /srv/php/core/main/main.c:2637
    #9 0x555556c1ee23 in do_cli /srv/php/core/sapi/cli/php_cli.c:1000
    #10 0x555556c2116e in main /srv/php/core/sapi/cli/php_cli.c:1396
    #11 0x7ffff653d0b2 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x270b2)

previously allocated by thread T0 here:
    #0 0x7ffff769abc8 in malloc (/usr/lib/x86_64-linux-gnu/libasan.so.5+0x10dbc8)
    #1 0x55555692f1e7 in __zend_malloc /srv/php/core/Zend/zend_alloc.c:2909
    #2 0x55555692d3f4 in _emalloc /srv/php/core/Zend/zend_alloc.c:2502
    #3 0x5555569eaec0 in _zend_new_array /srv/php/core/Zend/zend_hash.c:224
    #4 0x555556514406 in php_array_merge_or_replace_wrapper /srv/php/core/ext/standard/array.c:3796
    #5 0x555556514dbe in zif_array_merge /srv/php/core/ext/standard/array.c:3845
    #6 0x555556abb78d in ZEND_DO_ICALL_SPEC_RETVAL_USED_HANDLER /srv/php/core/Zend/zend_vm_execute.h:694
    #7 0x555556c0683a in execute_ex /srv/php/core/Zend/zend_vm_execute.h:55503
    #8 0x55555697f8c9 in zend_call_function /srv/php/core/Zend/zend_execute_API.c:756
    #9 0x555556a28e02 in zend_call_method /srv/php/core/Zend/zend_interfaces.c:103
    #10 0x555556a7d979 in zend_std_get_debug_info /srv/php/core/Zend/zend_object_handlers.c:155
    #11 0x55555666d327 in php_var_dump /srv/php/core/ext/standard/var.c:153
    #12 0x55555666dd5c in zif_var_dump /srv/php/core/ext/standard/var.c:210
    #13 0x555556abb16e in ZEND_DO_ICALL_SPEC_RETVAL_UNUSED_HANDLER /srv/php/core/Zend/zend_vm_execute.h:649
    #14 0x555556c06809 in execute_ex /srv/php/core/Zend/zend_vm_execute.h:55499
    #15 0x555556c17f26 in zend_execute /srv/php/core/Zend/zend_vm_execute.h:60935
    #16 0x5555569bc397 in zend_execute_scripts /srv/php/core/Zend/zend.c:1568
    #17 0x5555568611b2 in php_execute_script /srv/php/core/main/main.c:2637
    #18 0x555556c1ee23 in do_cli /srv/php/core/sapi/cli/php_cli.c:1000
    #19 0x555556c2116e in main /srv/php/core/sapi/cli/php_cli.c:1396
    #20 0x7ffff653d0b2 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x270b2)

SUMMARY: AddressSanitizer: heap-use-after-free /srv/php/core/Zend/zend_gc.c:976 in gc_mark_roots
Shadow bytes around the buggy address:
  0x0c0c7fffac80: fd fd fd fd fd fd fd fa fa fa fa fa 00 00 00 00
  0x0c0c7fffac90: 00 00 00 fa fa fa fa fa fd fd fd fd fd fd fd fd
  0x0c0c7fffaca0: fa fa fa fa fd fd fd fd fd fd fd fa fa fa fa fa
  0x0c0c7fffacb0: 00 00 00 00 00 00 00 fa fa fa fa fa 00 00 00 00
  0x0c0c7fffacc0: 00 00 00 fa fa fa fa fa fd fd fd fd fd fd fd fd
=>0x0c0c7fffacd0: fa fa fa fa[fd]fd fd fd fd fd fd fa fa fa fa fa
  0x0c0c7ffface0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c0c7fffacf0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c0c7fffad00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c0c7fffad10: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c0c7fffad20: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
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
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
  Shadow gap:              cc
==914259==ABORTING
[Inferior 1 (process 914259) exited with code 01]


Patches

Pull Requests

Pull requests:

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2021-03-22 11:35 UTC] tstarling@php.net
The following pull request has been associated:

Patch Name: Fix bug #80894: properly free debuginfo
On GitHub:  https://github.com/php/php-src/pull/6794
Patch:      https://github.com/php/php-src/pull/6794.patch
 [2021-03-22 11:36 UTC] tstarling@php.net
You will need to merge https://github.com/php/php-src/pull/6793 to reproduce the bug with AddressSanitizer.
 [2021-03-24 12:20 UTC] cmb@php.net
-Assigned To: +Assigned To: stas
 [2021-03-24 12:20 UTC] cmb@php.net
PHP-7.3 only receives security support[1], and this doesn't look
like a security issue according to our classification[2].  If it
is indeed not a security issue, and PHP-7.4+ is not affected, this
would be not a bug.

Stas, what do you think?

[1] <https://www.php.net/supported-versions.php>
[2] <https://wiki.php.net/security>
 [2021-03-24 17:55 UTC] stas@php.net
-Status: Assigned +Status: Wont fix
 [2021-03-24 17:55 UTC] stas@php.net
Doesn't look like security issue, so since the timer for 7,3 has run out, this would be a "won't fix".
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Fri Nov 01 23:01:29 2024 UTC