php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #79710 Reproducible segfault in error_handler during GC involved an SplFileObject
Submitted: 2020-06-18 07:10 UTC Modified: 2020-06-19 08:35 UTC
From: sam at hellosam dot net Assigned:
Status: Closed Package: Reproducible crash
PHP Version: 7.3Git-2020-06-18 (Git) OS: Ubuntu Linux 20.04 LTS
Private report: No CVE-ID: None
 [2020-06-18 07:10 UTC] sam at hellosam dot net
Description:
------------
Upon calling flock() on a destructed SplFileObject, which is being destructed eariler in the shutdown process while still accessible in another static object yet to be destructed, it will raise an error as expected and calling error_handler, but then the PHP error handling code would cause segmentation fault in the Zend VM engine.

It is beyond my knowledge to understand why that particular error handling code would cause error. The issue was found in my production system using CakePHP, I adopted a few lines of that in the repro script and could 100% reproduce the problem.

---

Affected version:
* 7.3 GIT 2020-06-13 (verified on 5621c5f)
* 7.3.19
* 7.2 GIT 2020-06-13 (verified on f5b1c32)
* 7.2.31
* On 7.4 branch - fe8fdfa3 is the last commit that shows the error behavior. e219ec144 fixed it. (This is by bisecting the master branch, I don't understand why though)
* On Ubuntu 18.04 LTS latest php-cli package [1:7.2+60ubuntu1] which is PHP 7.2.24-0ubuntu0.18.04.6

Unaffected version (Does not reproduce on):
* 7.4.7
* 7.4 GIT 2020-06-13
* On Ubuntu 20.04 LTS latest php-cli package [7.4.3-4ubuntu2.2] which is PHP 7.4.3

Except for the ubuntu package, I tested by building from GIT source with the following:
./buildconf && ./configure && make -j 4

Test script:
---------------
Repro script:
https://gist.githubusercontent.com/it9gamelog/1f4d0465c5a83faf488bf15c2927a01b/raw/f0a2b74c3837bf8d5bdb19ac15c2d13d53cde061/test.php

from GIST Link:
https://gist.github.com/it9gamelog/1f4d0465c5a83faf488bf15c2927a01b

Expected result:
----------------
Expecting seeing no segmentation fault.

Actual result:
--------------
GDB info with GIT fe8fdfa3 built from source on Ubuntu 20.04:

(gdb) run
Starting program: /home/sam/php-src/sapi/cli/php ../repro.php
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Handle Error 2, flock(): supplied resource is not a valid stream resource

Program received signal SIGSEGV, Segmentation fault.
zend_mm_alloc_small (bin_num=2, size=24, heap=0x7ffff5800040) at /home/sam/php-src/Zend/zend_alloc.c:1279
1279                    heap->free_slot[bin_num] = p->next_free_slot;


(gdb) backtrace
#0  zend_mm_alloc_small (bin_num=2, size=24, heap=0x7ffff5800040) at /home/sam/php-src/Zend/zend_alloc.c:1279
#1  _emalloc_24 () at /home/sam/php-src/Zend/zend_alloc.c:2447
#2  0x0000555555917a07 in ZEND_ADD_ARRAY_ELEMENT_SPEC_CV_UNUSED_HANDLER () at /home/sam/php-src/Zend/zend_vm_execute.h:46824
#3  0x000055555593cf8c in execute_ex (ex=0x7ffff5800040) at /home/sam/php-src/Zend/zend_vm_execute.h:60107
#4  0x00005555558b0321 in zend_call_function (fci=<optimized out>, fci_cache=0x7ffff586c140) at /home/sam/php-src/Zend/zend_execute_API.c:801
#5  0x00005555558b0619 in _call_user_function_ex (object=object@entry=0x0, function_name=function_name@entry=0x7fffffffbd50, retval_ptr=retval_ptr@entry=0x7fffffffbd40, param_count=param_count@entry=5,
    params=params@entry=0x7fffffffbdd0, no_separation=no_separation@entry=1) at /home/sam/php-src/Zend/zend_execute_API.c:643
#6  0x000055555565c114 in zend_error (type=type@entry=2, format=format@entry=0x555555f939a0 "%s%s%s(): supplied resource is not a valid %s resource") at /home/sam/php-src/Zend/zend.c:1393
#7  0x00005555558d108a in zend_fetch_resource2 (resource_type_name=resource_type_name@entry=0x555555f7f9f9 "stream", resource_type2=3, resource_type1=<optimized out>, res=<optimized out>) at /home/sam/php-src/Zend/zend_list.c:116
#8  0x00005555558d125d in zend_fetch_resource2 (res=<optimized out>, resource_type_name=resource_type_name@entry=0x555555f7f9f9 "stream", resource_type1=<optimized out>, resource_type2=resource_type2@entry=3)
    at /home/sam/php-src/Zend/zend_list.c:105
#9  0x00005555557fa144 in zif_flock (execute_data=0x7ffff581c0f0, return_value=0x7fffffffc080) at /home/sam/php-src/ext/standard/file.c:349
#10 0x00005555558b021f in zend_call_function (fci=fci@entry=0x7fffffffc0b0, fci_cache=fci_cache@entry=0x7fffffffc090) at /home/sam/php-src/Zend/zend_execute_API.c:815
#11 0x00005555557c675f in spl_filesystem_file_call (intern=<optimized out>, func_ptr=0x5555560ebbf0, pass_num_args=1, arg2=<optimized out>, return_value=<optimized out>, return_value=<optimized out>)
    at /home/sam/php-src/ext/spl/spl_directory.c:2089
#12 0x0000555555945445 in ZEND_DO_FCALL_SPEC_RETVAL_UNUSED_HANDLER () at /home/sam/php-src/Zend/zend_vm_execute.h:983
#13 execute_ex (ex=0x7ffff5800040) at /home/sam/php-src/Zend/zend_vm_execute.h:55163
#14 0x00005555558b0321 in zend_call_function (fci=fci@entry=0x7fffffffc2d0, fci_cache=0x7ffff588d160, fci_cache@entry=0x7fffffffc2b0) at /home/sam/php-src/Zend/zend_execute_API.c:801
#15 0x00005555558ee4b2 in zend_objects_destroy_object (object=0x7ffff585f348) at /home/sam/php-src/Zend/zend_objects.c:163
#16 0x00005555558f2ce6 in zend_objects_store_call_destructors (objects=objects@entry=0x5555560cef68 <executor_globals+840>) at /home/sam/php-src/Zend/zend_objects_API.c:55
#17 0x00005555558aeeab in shutdown_destructors () at /home/sam/php-src/Zend/zend_execute_API.c:242
#18 0x00005555558be0e5 in zend_call_destructors () at /home/sam/php-src/Zend/zend.c:1136
#19 0x00005555558603a5 in php_request_shutdown (dummy=<optimized out>) at /home/sam/php-src/main/main.c:1879
#20 0x0000555555947e20 in do_cli (argc=2, argv=0x5555560e5ae0) at /home/sam/php-src/sapi/cli/php_cli.c:1159
#21 0x0000555555675d18 in main (argc=2, argv=0x5555560e5ae0) at /home/sam/php-src/sapi/cli/php_cli.c:1384


(gdb) zbacktrace
[0x7ffff581c220] Hash->merge(array(1)[0x7ffff581c270], array(1)[0x7ffff581c280]) /home/sam/repro.php:13
[0x7ffff581c160] Run->handleError(2, "flock(): supplied resource is not a valid stream resource", , , "/home/sam/repro.php") /home/sam/repro.php:50
[0x7ffff581c0f0] flock(resource(#-176156384), 2) [internal function]
[0x7ffff581c090] SplFileObject->flock(2) [internal function]
[0x7ffff581c020] Target->__destruct() /home/sam/repro.php:27
[0x7fffffffc210] ???




Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2020-06-19 07:53 UTC] nikic@php.net
-Status: Open +Status: Verified
 [2020-06-19 07:53 UTC] nikic@php.net
This also happens on newer versions (7.4, master), it just doesn't crash. There's use-after-free under valgrind.
 [2020-06-19 08:35 UTC] nikic@php.net
Smaller reproducer for valgrind:

<?php
  
class Target
{
    public $sfo;
    public function __construct($sfo) {
        $this->sfo = $sfo;
    }
    public function __destruct() {
        // If the SplFileObject is destructed first,
        // underlying FD is no longer valid and will cause error upon calling flock
        $this->sfo->flock(2);
    }
}

class Run
{
    static $sfo;
    static $foo;
    public static function main() {
        // Creation ordering is important for repro
        // $sfo needed to be destructed before $foo.
        Run::$sfo = new SplTempFileObject();
        Run::$foo = new Target(Run::$sfo);
    }
}

Run::main();

First error:

==187903== Invalid read of size 4
==187903==    at 0xA02EBF: zend_gc_addref (zend_types.h:991)
==187903==    by 0xA0622B: zend_call_function (zend_execute_API.c:737)
==187903==    by 0x7BE28E: spl_filesystem_file_call (spl_directory.c:2096)
==187903==    by 0x7C02EF: zim_spl_SplFileObject_flock (spl_directory.c:2726)
==187903==    by 0xA8940E: ZEND_DO_FCALL_SPEC_RETVAL_UNUSED_HANDLER (zend_vm_execute.h:984)
==187903==    by 0xAF723F: execute_ex (zend_vm_execute.h:55527)
==187903==    by 0xA06339: zend_call_function (zend_execute_API.c:756)
==187903==    by 0xA6DFF8: zend_objects_destroy_object (zend_objects.c:159)
==187903==    by 0xA74AA9: zend_objects_store_call_destructors (zend_objects_API.c:57)
==187903==    by 0xA043CA: shutdown_destructors (zend_execute_API.c:242)
==187903==    by 0xA1CFC0: zend_call_destructors (zend.c:1089)
==187903==    by 0x980AE6: php_request_shutdown (main.c:1875)
==187903==  Address 0x9632490 is 0 bytes inside a block of size 24 free'd
==187903==    at 0x483CA3F: free (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==187903==    by 0x9E52C6: _efree (zend_alloc.c:2516)
==187903==    by 0xA3A21A: list_entry_destructor (zend_list.c:187)
==187903==    by 0xA34B24: _zend_hash_del_el_ex (zend_hash.c:1182)
==187903==    by 0xA3544C: zend_hash_index_del (zend_hash.c:1381)
==187903==    by 0xA39C99: zend_list_delete (zend_list.c:48)
==187903==    by 0x9A1889: _php_stream_free (streams.c:448)
==187903==    by 0x7B7E8B: spl_filesystem_object_destroy_object (spl_directory.c:94)
==187903==    by 0xA74AA9: zend_objects_store_call_destructors (zend_objects_API.c:57)
==187903==    by 0xA043CA: shutdown_destructors (zend_execute_API.c:242)
==187903==    by 0xA1CFC0: zend_call_destructors (zend.c:1089)
==187903==    by 0x980AE6: php_request_shutdown (main.c:1875)
==187903==  Block was alloc'd at
==187903==    at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==187903==    by 0x9E5FF1: __zend_malloc (zend_alloc.c:2909)
==187903==    by 0x9E5215: _emalloc (zend_alloc.c:2502)
==187903==    by 0xA39BC7: zend_list_insert (zend_list.c:41)
==187903==    by 0xA39E1A: zend_register_resource (zend_list.c:96)
==187903==    by 0x9A1577: _php_stream_alloc (streams.c:310)
==187903==    by 0x9A87EB: _php_stream_temp_create_ex (memory.c:586)
==187903==    by 0x9A88BB: _php_stream_temp_create (memory.c:598)
==187903==    by 0x8B5B95: php_stream_url_wrap_php (php_fopen_wrapper.c:207)
==187903==    by 0x9A5AE3: _php_stream_open_wrapper_ex (streams.c:2046)
==187903==    by 0x7B8722: spl_filesystem_file_open (spl_directory.c:299)
==187903==    by 0x7BEFF5: zim_spl_SplTempFileObject___construct (spl_directory.c:2338)
 [2020-06-19 08:48 UTC] nikic@php.net
Automatic comment on behalf of nikita.ppv@gmail.com
Revision: http://git.php.net/?p=php-src.git;a=commit;h=32f377b0b94482a5b126408942646b9bd101c042
Log: Fixed bug #79710
 [2020-06-19 08:48 UTC] nikic@php.net
-Status: Verified +Status: Closed
 
PHP Copyright © 2001-2020 The PHP Group
All rights reserved.
Last updated: Tue Aug 11 00:01:26 2020 UTC