mirror of
https://github.com/php/php-src.git
synced 2026-03-26 01:02:25 +01:00
Fix use-after-scope in SplObjectStorage::unserialize()
Introduced by the recent switch to a zend_object. Unserialize the object into a tmp_var to avoid leaving behind a stack reference. Fixes oss-fuzz #29271.
This commit is contained in:
@@ -682,7 +682,6 @@ PHP_METHOD(SplObjectStorage, unserialize)
|
||||
size_t buf_len;
|
||||
const unsigned char *p, *s;
|
||||
php_unserialize_data_t var_hash;
|
||||
zval entry, inf;
|
||||
zval *pcount, *pmembers;
|
||||
spl_SplObjectStorageElement *element;
|
||||
zend_long count;
|
||||
@@ -715,13 +714,12 @@ PHP_METHOD(SplObjectStorage, unserialize)
|
||||
goto outexcept;
|
||||
}
|
||||
|
||||
ZVAL_UNDEF(&entry);
|
||||
ZVAL_UNDEF(&inf);
|
||||
|
||||
while (count-- > 0) {
|
||||
spl_SplObjectStorageElement *pelement;
|
||||
zend_hash_key key;
|
||||
zval obj;
|
||||
zval *entry = var_tmp_var(&var_hash);
|
||||
zval inf;
|
||||
ZVAL_UNDEF(&inf);
|
||||
|
||||
if (*p != ';') {
|
||||
goto outexcept;
|
||||
@@ -731,46 +729,38 @@ PHP_METHOD(SplObjectStorage, unserialize)
|
||||
goto outexcept;
|
||||
}
|
||||
/* store reference to allow cross-references between different elements */
|
||||
if (!php_var_unserialize(&entry, &p, s + buf_len, &var_hash)) {
|
||||
zval_ptr_dtor(&entry);
|
||||
if (!php_var_unserialize(entry, &p, s + buf_len, &var_hash)) {
|
||||
goto outexcept;
|
||||
}
|
||||
if (*p == ',') { /* new version has inf */
|
||||
++p;
|
||||
if (!php_var_unserialize(&inf, &p, s + buf_len, &var_hash)) {
|
||||
zval_ptr_dtor(&entry);
|
||||
zval_ptr_dtor(&inf);
|
||||
goto outexcept;
|
||||
}
|
||||
}
|
||||
if (Z_TYPE(entry) != IS_OBJECT) {
|
||||
zval_ptr_dtor(&entry);
|
||||
if (Z_TYPE_P(entry) != IS_OBJECT) {
|
||||
zval_ptr_dtor(&inf);
|
||||
goto outexcept;
|
||||
}
|
||||
|
||||
if (spl_object_storage_get_hash(&key, intern, Z_OBJ(entry)) == FAILURE) {
|
||||
zval_ptr_dtor(&entry);
|
||||
if (spl_object_storage_get_hash(&key, intern, Z_OBJ_P(entry)) == FAILURE) {
|
||||
zval_ptr_dtor(&inf);
|
||||
goto outexcept;
|
||||
}
|
||||
pelement = spl_object_storage_get(intern, &key);
|
||||
spl_object_storage_free_hash(intern, &key);
|
||||
if (pelement) {
|
||||
zval obj;
|
||||
if (!Z_ISUNDEF(pelement->inf)) {
|
||||
var_push_dtor(&var_hash, &pelement->inf);
|
||||
}
|
||||
ZVAL_OBJ(&obj, pelement->obj);
|
||||
var_push_dtor(&var_hash, &obj);
|
||||
}
|
||||
element = spl_object_storage_attach(intern, Z_OBJ(entry), Z_ISUNDEF(inf)?NULL:&inf);
|
||||
ZVAL_OBJ(&obj, element->obj);
|
||||
var_replace(&var_hash, &entry, &obj);
|
||||
element = spl_object_storage_attach(intern, Z_OBJ_P(entry), Z_ISUNDEF(inf)?NULL:&inf);
|
||||
var_replace(&var_hash, &inf, &element->inf);
|
||||
zval_ptr_dtor(&entry);
|
||||
ZVAL_UNDEF(&entry);
|
||||
zval_ptr_dtor(&inf);
|
||||
ZVAL_UNDEF(&inf);
|
||||
}
|
||||
|
||||
if (*p != ';') {
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
--TEST--
|
||||
Reference to SplObjectStorage key (not supported)
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$inner = 'x:i:1;O:8:"stdClass":0:{};m:a:0:{}';
|
||||
$inner_len = strlen($inner);
|
||||
$str = <<<STR
|
||||
a:2:{i:0;C:16:"SPlObjectStorage":{$inner_len}:{{$inner}}i:1;R:4;}
|
||||
STR;
|
||||
var_dump(unserialize($str));
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
array(2) {
|
||||
[0]=>
|
||||
object(SplObjectStorage)#1 (1) {
|
||||
["storage":"SplObjectStorage":private]=>
|
||||
array(1) {
|
||||
["%s"]=>
|
||||
array(2) {
|
||||
["obj"]=>
|
||||
object(stdClass)#2 (0) {
|
||||
}
|
||||
["inf"]=>
|
||||
NULL
|
||||
}
|
||||
}
|
||||
}
|
||||
[1]=>
|
||||
object(stdClass)#2 (0) {
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user