Bug #61115 [Opn->Ana]: Stream related segfault on fatal error in php_stream_context_del_link
| From: | cataphract@php.net | Date: | Tue, 21 Feb 2012 19:33:32 +0000 |
| Subject: | Bug #61115 [Opn->Ana]: Stream related segfault on fatal error in php_stream_context_del_link | ||
| References: | 1 | Groups: | php.bugs |
| Request: | Send a blank email to php-bugs+get-167713@lists.php.net to get a copy of this message | ||
Edit report at https://bugs.php.net/bug.php?id=61115&edit=1
ID: 61115
Updated by: cataphract@php.net
Reported by: nikic@php.net
Summary: Stream related segfault on fatal error in
php_stream_context_del_link
-Status: Open
+Status: Analyzed
Type: Bug
Package: Reproducible crash
PHP Version: 5.4.0RC7
Block user comment: N
Private report: N
New Comment:
I don't think this can be solved without significant changes.
The stream stores a pointer directly to the context structure (and increments the context resource
refcount), but on an unorderly shutdown the resources are simply destroyed in inverse order of
created. _php_stream_free then makes invalid reads, not just on the place that causes this segfault,
but also near the end when it tries to decrease the context refcount.
I think the solution here would be to have the stream store the context resource id instead of the
context structure (basically adding one level of indirection). We may be able to this without
breaking binary compatibility, and the details of the stream structure are supposedly private (see
comment on php_streams.h), but I have no doubt this would be a very problematic change nonetheless.
Previous Comments:
------------------------------------------------------------------------
[2012-02-16 21:59:09] nikic@php.net
Description:
------------
<?php
$arrayLarge = array_fill(0, 113663, '*');
$resourceFileTemp = fopen('php://temp', 'wr');
stream_context_set_params($resourceFileTemp, array());
preg_replace('', function () { }, $resourceFileTemp);
The above script produces a segfault. The array_fill line is irrelevant for the
bug itself, but I needed it to get a segfault on non-debug builds too (without
it it only segfaulted on debug builds.)
The type of the file resource is irrelevant, it is not restricted to php://temp.
The preg_replace + function() { } only serves the purpose to create a fatal
error with the file argument, but apart from that should be irrelevant (it also
occurs in lots of other situations that create a fatal error in a function
call.)
This segfault basically occurs in situations where:
1. A file resource is opened
2. Some stream operation is performed on it
3. A fatal error is issued from a function which the file resource was passed to
Here is the backtrace:
(gdb) run workingFile5_segfault.php
Starting program: /usr/local/bin/php workingFile5_segfault.php
[Thread debugging using libthread_db enabled]
Catchable fatal error: Object of class Closure could not be converted to string
in /home/nikic/dev/my-fuzzer/results/workingFile5_segfault.php on line 8
Program received signal SIGSEGV, Segmentation fault.
0x084c95cb in php_stream_context_del_link (context=0xb73cbddc,
stream=0xb73cba00) at /home/nikic/dev/php-src/main/streams/streams.c:2256
2256 for(zend_hash_internal_pointer_reset(Z_ARRVAL_P(context-
>links));
(gdb) bt
#0 0x084c95cb in php_stream_context_del_link (context=0xb73cbddc,
stream=0xb73cba00) at /home/nikic/dev/php-src/main/streams/streams.c:2256
#1 0x084c4953 in _php_stream_free (stream=0xb73cba00, close_options=3,
tsrm_ls=0x8b26050) at /home/nikic/dev/php-src/main/streams/streams.c:449
#2 0x084c48a4 in _php_stream_free (stream=0xb73cbb90, close_options=11,
tsrm_ls=0x8b26050) at /home/nikic/dev/php-src/main/streams/streams.c:406
#3 0x084c7059 in stream_resource_regular_dtor (rsrc=0xb73cbca0,
tsrm_ls=0x8b26050) at /home/nikic/dev/php-src/main/streams/streams.c:1578
#4 0x085587f3 in list_entry_destructor (ptr=0xb73cbca0)
at /home/nikic/dev/php-src/Zend/zend_list.c:183
#5 0x08555fc6 in zend_hash_apply_deleter (ht=0x8b280ac, p=0xb73cbc4c)
at /home/nikic/dev/php-src/Zend/zend_hash.c:650
#6 0x08556154 in zend_hash_graceful_reverse_destroy (ht=0x8b280ac)
at /home/nikic/dev/php-src/Zend/zend_hash.c:687
#7 0x085589d5 in zend_destroy_rsrc_list (ht=0x8b280ac, tsrm_ls=0x8b26050)
at /home/nikic/dev/php-src/Zend/zend_list.c:239
#8 0x0854474a in zend_deactivate (tsrm_ls=0x8b26050)
at /home/nikic/dev/php-src/Zend/zend.c:940
#9 0x084a6b4d in php_request_shutdown (dummy=0x0)
at /home/nikic/dev/php-src/main/main.c:1781
#10 0x086907c5 in do_cli (argc=2, argv=0xbffff3d4, tsrm_ls=0x8b26050)
at /home/nikic/dev/php-src/sapi/cli/php_cli.c:1169
#11 0x08691058 in main (argc=2, argv=0xbffff3d4)
at /home/nikic/dev/php-src/sapi/cli/php_cli.c:1356
I was not yet able to understand the source of the segfault; would be nice if
someone who knows the stream stuff better could give a hand :)
------------------------------------------------------------------------
--
Edit this bug report at https://bugs.php.net/bug.php?id=61115&edit=1