diff --git a/Zend/tests/gh22257.phpt b/Zend/tests/gh22257.phpt new file mode 100644 index 000000000000..aaee9da835d6 --- /dev/null +++ b/Zend/tests/gh22257.phpt @@ -0,0 +1,29 @@ +--TEST-- +GH-22257 (Type confusion / OOB read unserializing an Exception with a non-array trace) +--CREDITS-- +Igor Sak-Sakovskiy (Positive Technologies) +--FILE-- +getPrevious()) { + printf("%s: %s\n", $e::class, $e->getMessage()); + } +} +echo "OK\n"; +?> +--EXPECTF-- +Warning: unserialize(): Error at offset %d of %d bytes in %s on line %d +OK diff --git a/ext/standard/var_unserializer.re b/ext/standard/var_unserializer.re index d5019d94dc0c..29d2f41f6e2b 100644 --- a/ext/standard/var_unserializer.re +++ b/ext/standard/var_unserializer.re @@ -677,10 +677,17 @@ second_try: } if (!php_var_unserialize_internal(data, p, max, var_hash)) { - if (info && Z_ISREF_P(data)) { - /* Add type source even if we failed to unserialize. - * The data is still stored in the property. */ - ZEND_REF_ADD_TYPE_SOURCE(Z_REF_P(data), info); + if (info) { + if (Z_ISREF_P(data)) { + ZEND_REF_ADD_TYPE_SOURCE(Z_REF_P(data), info); + } else { + /* "partially unserialized" value might violate the property + * declared type so we restore the default + */ + zval *tmp = &obj->ce->default_properties_table[OBJ_PROP_TO_NUM(info->offset)]; + zval_ptr_dtor(data); + ZVAL_COPY_OR_DUP(data, tmp); + } } goto failure; }