mirror of
https://github.com/php/php-src.git
synced 2025-08-16 05:58:45 +02:00
Fix use-after-free when unregistering user stream wrapper from itself
Fixes GH-11735
Closes GH-11737
(cherry picked from commit c3ccc363c6
)
This commit is contained in:
parent
8b1d352ed8
commit
4e35ee0109
3 changed files with 39 additions and 4 deletions
16
Zend/tests/gh11735_1.phpt
Normal file
16
Zend/tests/gh11735_1.phpt
Normal file
|
@ -0,0 +1,16 @@
|
|||
--TEST--
|
||||
GH-11735: Use-after-free when unregistering user stream wrapper from user stream wrapper
|
||||
--FILE--
|
||||
<?php
|
||||
class FooWrapper {
|
||||
public $context;
|
||||
public function stream_open($path, $mode, $options, &$opened_path) {
|
||||
stream_wrapper_unregister('foo');
|
||||
return true;
|
||||
}
|
||||
}
|
||||
stream_wrapper_register('foo', 'FooWrapper');
|
||||
var_dump(fopen('foo://bar', 'r'));
|
||||
?>
|
||||
--EXPECTF--
|
||||
resource(%d) of type (stream)
|
17
Zend/tests/gh11735_2.phpt
Normal file
17
Zend/tests/gh11735_2.phpt
Normal file
|
@ -0,0 +1,17 @@
|
|||
--TEST--
|
||||
GH-11735: Use-after-free when unregistering user stream wrapper from user stream wrapper
|
||||
--FILE--
|
||||
<?php
|
||||
class FooWrapper {
|
||||
public $context;
|
||||
public function stream_open($path, $mode, $options, &$opened_path) {
|
||||
stream_wrapper_unregister('foo');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
stream_wrapper_register('foo', 'FooWrapper');
|
||||
var_dump(fopen('foo://bar', 'r'));
|
||||
?>
|
||||
--EXPECTF--
|
||||
Warning: fopen(foo://bar): Failed to open stream: "FooWrapper::stream_open" call failed in %s on line %d
|
||||
bool(false)
|
|
@ -341,6 +341,8 @@ static php_stream *user_wrapper_opener(php_stream_wrapper *wrapper, const char *
|
|||
|
||||
us = emalloc(sizeof(*us));
|
||||
us->wrapper = uwrap;
|
||||
/* call_method_if_exists() may unregister the stream wrapper. Hold on to it. */
|
||||
GC_ADDREF(us->wrapper->resource);
|
||||
|
||||
user_stream_create_object(uwrap, context, &us->object);
|
||||
if (Z_TYPE(us->object) == IS_UNDEF) {
|
||||
|
@ -376,8 +378,6 @@ static php_stream *user_wrapper_opener(php_stream_wrapper *wrapper, const char *
|
|||
|
||||
/* set wrapper data to be a reference to our object */
|
||||
ZVAL_COPY(&stream->wrapperdata, &us->object);
|
||||
|
||||
GC_ADDREF(us->wrapper->resource);
|
||||
} else {
|
||||
php_stream_wrapper_log_error(wrapper, options, "\"%s::" USERSTREAM_OPEN "\" call failed",
|
||||
ZSTR_VAL(us->wrapper->ce->name));
|
||||
|
@ -387,6 +387,7 @@ static php_stream *user_wrapper_opener(php_stream_wrapper *wrapper, const char *
|
|||
if (stream == NULL) {
|
||||
zval_ptr_dtor(&us->object);
|
||||
ZVAL_UNDEF(&us->object);
|
||||
zend_list_delete(us->wrapper->resource);
|
||||
efree(us);
|
||||
}
|
||||
zval_ptr_dtor(&zretval);
|
||||
|
@ -429,6 +430,8 @@ static php_stream *user_wrapper_opendir(php_stream_wrapper *wrapper, const char
|
|||
|
||||
us = emalloc(sizeof(*us));
|
||||
us->wrapper = uwrap;
|
||||
/* call_method_if_exists() may unregister the stream wrapper. Hold on to it. */
|
||||
GC_ADDREF(us->wrapper->resource);
|
||||
|
||||
user_stream_create_object(uwrap, context, &us->object);
|
||||
if (Z_TYPE(us->object) == IS_UNDEF) {
|
||||
|
@ -451,8 +454,6 @@ static php_stream *user_wrapper_opendir(php_stream_wrapper *wrapper, const char
|
|||
|
||||
/* set wrapper data to be a reference to our object */
|
||||
ZVAL_COPY(&stream->wrapperdata, &us->object);
|
||||
|
||||
GC_ADDREF(us->wrapper->resource);
|
||||
} else {
|
||||
php_stream_wrapper_log_error(wrapper, options, "\"%s::" USERSTREAM_DIR_OPEN "\" call failed",
|
||||
ZSTR_VAL(us->wrapper->ce->name));
|
||||
|
@ -462,6 +463,7 @@ static php_stream *user_wrapper_opendir(php_stream_wrapper *wrapper, const char
|
|||
if (stream == NULL) {
|
||||
zval_ptr_dtor(&us->object);
|
||||
ZVAL_UNDEF(&us->object);
|
||||
zend_list_delete(us->wrapper->resource);
|
||||
efree(us);
|
||||
}
|
||||
zval_ptr_dtor(&zretval);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue