Skip to content

Argument corruption when calling XMLReader::open or XMLReader::XML non-statically with observer active #11548

Closed

Description

@tstarling

Description

Run this with the tideways_xhprof extension enabled:

<?php
class ObserverTest {
	public function __construct() {
		$reader = new XMLReader();
		$reader->XML( '<root></root>', null, 0 );
		print libxml_get_last_error() . "\n";
	}
}

new ObserverTest;

The $flags argument to XMLReader::XML() becomes garbage. It is a heap address.

Run under gdb to make it more obvious:

gdb --args php8.2 -d extension=tideways_xhprof xmlreader.php
...
(gdb) source .gdbinit
(gdb) break zim_XMLReader_XML
Function "zim_XMLReader_XML" not defined.
Make breakpoint pending on future shared library load? (y or [n]) y
Breakpoint 1 (zim_XMLReader_XML) pending.
(gdb) run
Starting program: /usr/bin/php8.2 -d extension=tideways_xhprof xmlreader.php
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

Breakpoint 1, zim_XMLReader_XML (execute_data=0x7ffff4e13170, return_value=0x7fffffffaa48) at ./ext/xmlreader/php_xmlreader.c:1013
1013    {
(gdb) zbacktrace
[0x7ffff4e13170] XMLReader->XML("<root></root>", NULL, 140737301786784) [internal function]
[0x7ffff4e130a0] ObserverTest->__construct() /home/tstarling/src/php/php8.2-8.2.7/xmlreader.php:6 
[0x7ffff4e13020] (main) /home/tstarling/src/php/php8.2-8.2.7/xmlreader.php:11 

Depending on what bits are set in the heap address passed for $flags, libxml_get_last_error() may return an error.

Setting a hardware watchpoint indicates that this assignment on line 236 of zend_observer.c is overwriting the argument, which at this point is already on the VM stack:

		*prev_observed_frame(execute_data) = current_observed_frame;

Note that XMLReader::XML() and XMLReader::open() are special in that they can be called either statically or non-statically. The bug occurs when calling them non-statically.

Downstream bug: https://phabricator.wikimedia.org/T330464

PHP Version

PHP 8.2.7

Operating System

Ubuntu 22.04

Activity

  1. damianwadley commented on Jun 28, 2023

    @damianwadley
    Member

    Confirmed, but if a bug only reproduces when an extension is installed...

    #0  zim_XMLReader_XML (execute_data=0x7ffff0208170, return_value=0x7fffffffb0c0)
        at /home/ubuntu/php/php-8.2.7/src/ext/xmlreader/php_xmlreader.c:1013
    #1  0x0000555556910777 in execute_internal (execute_data=0x7ffff0208170, return_value=0x7fffffffb0c0)
        at /home/ubuntu/php/php-8.2.7/src/Zend/zend_execute.c:3731
    #2  0x00007ffff079cb87 in tideways_xhprof_execute_internal (execute_data=0x7ffff0208170, return_value=0x7fffffffb0c0)
        at /home/ubuntu/php/php-profiler-extension/tideways_xhprof.c:234
    #3  0x00005555569277cf in ZEND_DO_FCALL_SPEC_OBSERVER_HANDLER () at /home/ubuntu/php/php-8.2.7/src/Zend/zend_vm_execute.h:2063
    #4  0x0000555556a6a872 in execute_ex (ex=0x7ffff0208020) at /home/ubuntu/php/php-8.2.7/src/Zend/zend_vm_execute.h:56072
    #5  0x0000555556a7d515 in zend_execute (op_array=0x7ffff028a140, return_value=0x0)
        at /home/ubuntu/php/php-8.2.7/src/Zend/zend_vm_execute.h:60396
    #6  0x00005555568820d7 in zend_execute_scripts (type=8, retval=0x0, file_count=3) at /home/ubuntu/php/php-8.2.7/src/Zend/zend.c:1827
    #7  0x000055555670db86 in php_execute_script (primary_file=0x7fffffffcc70) at /home/ubuntu/php/php-8.2.7/src/main/main.c:2542
    #8  0x0000555556c52ff6 in do_cli (argc=4, argv=0x604000000290) at /home/ubuntu/php/php-8.2.7/src/sapi/cli/php_cli.c:964
    #9  0x0000555556c54d2c in main (argc=4, argv=0x604000000290) at /home/ubuntu/php/php-8.2.7/src/sapi/cli/php_cli.c:1333
    

    Suggests the bug is in the extension.

    And I can't help but notice that the extension hasn't been updated since PHP 8.0...

  2. tstarling commented on Jun 28, 2023

    @tstarling
    ContributorAuthor

    Confirmed, but if a bug only reproduces when an extension is installed...
    Suggests the bug is in the extension.

    And I can't help but notice that the extension hasn't been updated since PHP 8.0...

    I reproduced it with the zend_test extension on the current git master:

    gdb --args sapi/cli/php -d zend_test.observer.enabled=1 -d zend_test.observer.observe_functions=1 xmlreader.php
    ...
    (gdb) zbacktrace
    [0x7ffff4215170] XMLReader->XML("<root></root>", NULL, 140737289212064) [internal function]
    
  3. Girgias commented on Jun 28, 2023

    @Girgias
    Member

    Assigning @bwoebi as they know something about the observer API AFAIK

  4. bwoebi commented on Jun 30, 2023

    @bwoebi
    Member

    That's really the worst hack :-)
    XMLReader::open and XMLReader::XML are copied in minit, then returned directly in xmlreader_get_method.
    The functions not being properly registered causes them to be skipped over in zend_observer_post_startup, which adds the temporary for all registered functions.

  5. added a commit that references this issue on Jun 30, 2023
    cad47be
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions