From 8c312ba74b763bee4c3cb2d5a5c80e5f4b046b92 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Tue, 16 Jul 2024 11:55:55 +0200 Subject: [PATCH] Fix use-after-free in property coercion with __toString() This was only partially fixed in PHP-8.3. Backports and fixes the case for both initialized and uninitialized property writes. Fixes GH-14969 Closes GH-14971 --- NEWS | 2 ++ Zend/tests/gh14969.phpt | 47 +++++++++++++++++++++++++++++++++++++ Zend/zend_object_handlers.c | 4 ++-- 3 files changed, 51 insertions(+), 2 deletions(-) create mode 100644 Zend/tests/gh14969.phpt diff --git a/NEWS b/NEWS index d5aa0983d59..2276e3ff22b 100644 --- a/NEWS +++ b/NEWS @@ -10,6 +10,8 @@ PHP NEWS (nielsdos) . Fixed OSS-Fuzz #69765. (nielsdos) . Fixed bug GH-14741 (Segmentation fault in Zend/zend_types.h). (nielsdos) + . Fixed bug GH-14969 (Use-after-free in property coercion with __toString()). + (ilutov) - Dom: . Fixed bug GH-14702 (DOMDocument::xinclude() crash). (nielsdos) diff --git a/Zend/tests/gh14969.phpt b/Zend/tests/gh14969.phpt new file mode 100644 index 00000000000..dedbaa7456e --- /dev/null +++ b/Zend/tests/gh14969.phpt @@ -0,0 +1,47 @@ +--TEST-- +GH-14969: Crash on coercion with throwing __toString() +--FILE-- +prop = $c; +} catch (Throwable $e) { + echo $e->getMessage(), "\n"; +} +var_dump($d); + +$c = new C(); +$d->prop = 'foo'; +try { + $d->prop = $c; +} catch (Throwable $e) { + echo $e->getMessage(), "\n"; +} +var_dump($d); + +?> +--EXPECTF-- +C::__toString +object(D)#%d (0) { + ["prop"]=> + uninitialized(string) +} +C::__toString +object(D)#2 (1) { + ["prop"]=> + string(3) "foo" +} diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index 58301da038c..d4586e53e4b 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -819,7 +819,7 @@ ZEND_API zval *zend_std_write_property(zend_object *zobj, zend_string *name, zva ZVAL_COPY_VALUE(&tmp, value); if (UNEXPECTED(!zend_verify_property_type(prop_info, &tmp, property_uses_strict_types()))) { - Z_TRY_DELREF_P(value); + zval_ptr_dtor(&tmp); variable_ptr = &EG(error_zval); goto exit; } @@ -890,7 +890,7 @@ write_std_property: ZVAL_COPY_VALUE(&tmp, value); if (UNEXPECTED(!zend_verify_property_type(prop_info, &tmp, property_uses_strict_types()))) { - zval_ptr_dtor(value); + zval_ptr_dtor(&tmp); goto exit; } value = &tmp;