Bug #79820 [Com]: double-free causing heap corruption
| From: | christopher dot broadbent at zencontrol dot com | Date: | Tue, 14 Jul 2020 00:41:34 +0000 |
| Subject: | Bug #79820 [Com]: double-free causing heap corruption | ||
| References: | 1 | Groups: | php.bugs |
| Request: | Send a blank email to php-bugs+get-228017@lists.php.net to get a copy of this message | ||
Edit report at https://bugs.php.net/bug.php?id=79820&edit=1
ID: 79820
Comment by: christopher dot broadbent at zencontrol dot com
Reported by: christopher dot broadbent at zencontrol dot com
Summary: double-free causing heap corruption
Status: Open
Type: Bug
Package: Reproducible crash
Operating System: linux debian buster
PHP Version: 7.4.7
Block user comment: N
Private report: N
New Comment:
Have build 7.4.8 from source .tar.gz file on website, it exhibits the same crash. Trying to get it
built and run with sanitizers now in case they give anything useful.
Previous Comments:
------------------------------------------------------------------------
[2020-07-13 23:54:05] christopher dot broadbent at zencontrol dot com
Upgraded to 7.4.8, still crashes.
> I can't find any version of PHP 7.4 that has a zend_string_release call in
> php_reflection.c:225
This might be the inline of the release call being assigned weird line numbers as it runs? The frame
#4 reflection_free_objects_storage (object=0x7ff047a6cb18) at ./ext/reflection/php_reflection.c:230
is calling:
zend_string_release(ZEND_TYPE_NAME(type_ref->type));
Regardless, I've asked the package maintainer if there are any patches applied before he
builds: https://github.com/oerdnj/deb.sury.org/issues/1433
I doubt that is the problem though as we're also hitting this issue on the official docker
containers, and they don't seem to do any patching.
Docker images: https://hub.docker.com/layers/php/library/php/7.4.8-buster/images/sha256-96e4c07b30977303a1bc53a269ea5284b3d85d4d89787948c3a594dc89a03698?context=explore
Docker image source: https://github.com/docker-library/php/tree/master/7.4/buster
------------------------------------------------------------------------
[2020-07-09 08:47:51] nikic@php.net
Not seeing what could cause this. Property types getting resolved while being held by reflection is
something we specifically protect against.
------------------------------------------------------------------------
[2020-07-09 08:41:17] nikic@php.net
On which version/commit of PHP were the gdb backtraces gathered? I can't find any version of
PHP 7.4 that has a zend_string_release call in php_reflection.c:225. The valgrind trace looks more
plausible.
There might be some relation to https://github.com/php/php-src/commit/c9abfaec6bf61bcef6d9651827b49cc7789018fd.
------------------------------------------------------------------------
[2020-07-09 05:44:47] christopher dot broadbent at zencontrol dot com
Description:
------------
We're currently hitting a fairly random segfault inside PHP. It's reproducible on each
run, but we're having difficulty making a minimal reproduction case to upload here.
The builds we're using are from https://deb.sury.org/, but
we're also hitting the problem on the builds from docker.io
I have a capture running under the rr debugger, and have the first free with a backtrace of
#0 zend_mm_free_small (bin_num=<optimized out>, ptr=0x7ff047a6caf0, heap=<optimized
out>) at ./Zend/zend_alloc.c:1279
#1 zend_mm_free_heap (ptr=0x7ff047a6caf0, heap=<optimized out>) at ./Zend/zend_alloc.c:1370
#2 _efree (ptr=0x7ff047a6caf0) at ./Zend/zend_alloc.c:2550
#3 0x000056422fc1cb24 in zend_objects_store_del (object=0x7ff047a6cb18) at
./Zend/zend_objects_API.c:197
#4 0x000056422fc6c92f in zend_object_release (obj=<optimized out>) at
./Zend/zend_objects_API.h:75
#5 ZEND_DO_FCALL_SPEC_RETVAL_USED_HANDLER () at ./Zend/zend_vm_execute.h:1767
#6 execute_ex (ex=0x7ff047a6caf0) at ./Zend/zend_vm_execute.h:53830
#7 0x000056422fc6da71 in zend_execute (op_array=0x7ff04a27f2a0, return_value=<optimized out>)
at ./Zend/zend_vm_execute.h:57922
#8 0x000056422fbe74b3 in zend_execute_scripts (type=type@entry=0x8, retval=0x7ff04a21ca80,
retval@entry=0x0, file_count=file_count@entry=0x3) at ./Zend/zend.c:1672
#9 0x000056422fb86b70 in php_execute_script (primary_file=<optimized out>) at
./main/main.c:2621
#10 0x000056422fc6fb86 in do_cli (argc=0xb, argv=0x564230f0cf40) at ./sapi/cli/php_cli.c:961
#11 0x000056422fa4e96b in main (argc=0xb, argv=0x564230f0cf40) at ./sapi/cli/php_cli.c:1356
and the double free has a backtrace of
#0 0x000056422fbc1e4b in zend_mm_free_small (bin_num=<optimized out>, ptr=0x7ff047a6caf0,
heap=0x7ff04a200040) at ./Zend/zend_alloc.c:1278
#1 zend_mm_free_heap (ptr=0x7ff047a6caf0, heap=0x7ff04a200040) at ./Zend/zend_alloc.c:1370
#2 _efree (ptr=0x7ff047a6caf0) at ./Zend/zend_alloc.c:2550
#3 0x000056422fac9ce4 in zend_string_release (s=<optimized out>) at
./ext/reflection/php_reflection.c:225
#4 reflection_free_objects_storage (object=0x7ff047a6cb18) at ./ext/reflection/php_reflection.c:230
#5 0x000056422fc1cb66 in zend_objects_store_del (object=0x7ff047a6cb18) at
./Zend/zend_objects_API.c:193
#6 0x000056422fc6c92f in zend_object_release (obj=<optimized out>) at
./Zend/zend_objects_API.h:75
#7 ZEND_DO_FCALL_SPEC_RETVAL_USED_HANDLER () at ./Zend/zend_vm_execute.h:1767
#8 execute_ex (ex=0x7ff047a6caf0) at ./Zend/zend_vm_execute.h:53830
#9 0x000056422fc6da71 in zend_execute (op_array=0x7ff04a27f2a0, return_value=<optimized out>)
at ./Zend/zend_vm_execute.h:57922
#10 0x000056422fbe74b3 in zend_execute_scripts (type=type@entry=0x8, retval=0x7ff04a21ca80,
retval@entry=0x0, file_count=file_count@entry=0x3) at ./Zend/zend.c:1672
#11 0x000056422fb86b70 in php_execute_script (primary_file=<optimized out>) at
./main/main.c:2621
#12 0x000056422fc6fb86 in do_cli (argc=0xb, argv=0x564230f0cf40) at ./sapi/cli/php_cli.c:961
#13 0x000056422fa4e96b in main (argc=0xb, argv=0x564230f0cf40) at ./sapi/cli/php_cli.c:1356
This sticks the heap in to a state where
(rr) p $heap->free_slot[8]
$59 = (zend_mm_free_slot *) 0x7ff047a6caf0
(rr) p $heap->free_slot[8]->next_free_slot
$60 = (zend_mm_free_slot *) 0x7ff047a6caf0
(rr) p $heap->free_slot[8]->next_free_slot->next_free_slot
$61 = (zend_mm_free_slot *) 0x7ff047a6caf0
etc, and ends up segfaulting on the second-next allocation
Running under valgrind gives a double free in a sightly different place:
USE_ZEND_ALLOC=0 valgrind -- php our_args
outputs a lot of..stuff before eventually crashing with
==29090== Invalid free() / delete / delete[] / realloc()
==29090== at 0x48369AB: free (vg_replace_malloc.c:530)
==29090== by 0x28ACE3: zend_string_release (zend_string.h:277)
==29090== by 0x28ACE3: reflection_free_objects_storage (php_reflection.c:230)
==29090== by 0x3DDB65: zend_objects_store_del (zend_objects_API.c:193)
==29090== by 0x42D92E: zend_object_release (zend_objects_API.h:75)
==29090== by 0x42D92E: ZEND_DO_FCALL_SPEC_RETVAL_USED_HANDLER (zend_vm_execute.h:1767)
==29090== by 0x42D92E: execute_ex (zend_vm_execute.h:53830)
==29090== by 0x42EA70: zend_execute (zend_vm_execute.h:57922)
==29090== by 0x3A84B2: zend_execute_scripts (zend.c:1672)
==29090== by 0x347B6F: php_execute_script (main.c:2621)
==29090== by 0x430B85: do_cli (php_cli.c:961)
==29090== by 0x20F96A: main (php_cli.c:1356)
==29090== Address 0xc432c40 is 0 bytes inside a block of size 80 free'd
==29090== at 0x48369AB: free (vg_replace_malloc.c:530)
==29090== by 0x3E3E64: zend_string_release (zend_string.h:277)
==29090== by 0x3E3E64: zend_resolve_class_type (zend_execute.c:947)
==29090== by 0x410B64: i_zend_check_property_type (zend_execute.c:961)
==29090== by 0x410B64: i_zend_verify_property_type (zend_execute.c:984)
==29090== by 0x410B64: zend_verify_property_type (zend_execute.c:993)
==29090== by 0x3DBA85: zend_std_write_property (zend_object_handlers.c:897)
==29090== by 0x3B244E: zend_update_property_ex (zend_API.c:4115)
==29090== by 0x289C4B: zim_reflection_property_setValue (php_reflection.c:5485)
==29090== by 0x42DE5F: ZEND_DO_FCALL_SPEC_RETVAL_UNUSED_HANDLER (zend_vm_execute.h:1618)
==29090== by 0x42DE5F: execute_ex (zend_vm_execute.h:53826)
==29090== by 0x42EA70: zend_execute (zend_vm_execute.h:57922)
==29090== by 0x3A84B2: zend_execute_scripts (zend.c:1672)
==29090== by 0x347B6F: php_execute_script (main.c:2621)
==29090== by 0x430B85: do_cli (php_cli.c:961)
==29090== by 0x20F96A: main (php_cli.c:1356)
==29090== Block was alloc'd at
==29090== at 0x483577F: malloc (vg_replace_malloc.c:299)
==29090== by 0x37EF38: __zend_malloc (zend_alloc.c:2976)
==29090== by 0x38629B: zend_string_alloc (zend_string.h:133)
==29090== by 0x38629B: zend_concat3 (zend_compile.c:791)
==29090== by 0x387243: zend_compile_typename (zend_compile.c:5318)
==29090== by 0x38BF6F: zend_compile_prop_decl (zend_compile.c:6100)
==29090== by 0x393EF0: zend_compile_prop_group (zend_compile.c:6178)
==29090== by 0x393EF0: zend_compile_stmt (zend_compile.c:8538)
==29090== by 0x394E46: zend_compile_stmt_list (zend_compile.c:5262)
==29090== by 0x394E46: zend_compile_stmt_list (zend_compile.c:5257)
==29090== by 0x393D59: zend_compile_stmt (zend_compile.c:8479)
==29090== by 0x395BDD: zend_compile_class_decl (zend_compile.c:6467)
==29090== by 0x396AA6: zend_compile_top_stmt (zend_compile.c:8454)
==29090== by 0x396ACF: zend_compile_top_stmt (zend_compile.c:8443)
==29090== by 0x36E844: zend_compile (zend_language_scanner.l:614)
I can probably get the full run from the rr debugger uploaded, as well as the valgrind logs, if
needed
$ php -m
[PHP Modules]
amqp
bcmath
calendar
Core
ctype
curl
date
dom
exif
FFI
fileinfo
filter
ftp
gettext
hash
iconv
intl
json
libxml
mbstring
mysqli
mysqlnd
openssl
pcntl
pcre
PDO
pdo_mysql
Phar
posix
rdkafka
readline
redis
Reflection
session
shmop
SimpleXML
sockets
sodium
SPL
standard
sysvmsg
sysvsem
sysvshm
tokenizer
xml
xmlreader
xmlwriter
xsl
Zend OPcache
zlib
[Zend Modules]
Zend OPcache
------------------------------------------------------------------------
--
Edit this bug report at https://bugs.php.net/bug.php?id=79820&edit=1