1
0
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:
Nikita Popov
2021-01-05 12:43:19 +01:00
parent 0067c3ced1
commit d29d3a4bf6
2 changed files with 41 additions and 18 deletions

View File

@@ -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 != ';') {

View File

@@ -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) {
}
}