From 9ab9dc23bf19fb346a5c93ab0c2e339858982400 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Sat, 11 Jan 2025 11:26:59 +0100 Subject: [PATCH] Fix GH-17442: Engine UAF with reference assign and dtor --- Zend/tests/weakrefs/gh17442.phpt | 22 +++++++++++ Zend/zend_API.h | 64 ++++++++++++++++++++++++-------- 2 files changed, 70 insertions(+), 16 deletions(-) create mode 100644 Zend/tests/weakrefs/gh17442.phpt diff --git a/Zend/tests/weakrefs/gh17442.phpt b/Zend/tests/weakrefs/gh17442.phpt new file mode 100644 index 0000000000000..8fd675629b7a9 --- /dev/null +++ b/Zend/tests/weakrefs/gh17442.phpt @@ -0,0 +1,22 @@ +--TEST-- +GH-17442 (Engine UAF with reference assign and dtor) +--CREDITS-- +YuanchengJiang +--FILE-- + +--EXPECTF-- +Fatal error: Uncaught Exception: Test in %s:%d +Stack trace: +#0 [internal function]: class@anonymous->__destruct() +#1 %s(%d): headers_sent('', 0) +#2 {main} + thrown in %s on line %d diff --git a/Zend/zend_API.h b/Zend/zend_API.h index 59d489f7aeea2..0b5f0f96b9475 100644 --- a/Zend/zend_API.h +++ b/Zend/zend_API.h @@ -1100,8 +1100,10 @@ ZEND_API zend_result zend_try_assign_typed_ref_zval_ex(zend_reference *ref, zval } \ _zv = &ref->val; \ } \ - zval_ptr_dtor(_zv); \ + zval garbage; \ + ZVAL_COPY_VALUE(&garbage, _zv); \ ZVAL_NULL(_zv); \ + zval_ptr_dtor(&garbage); \ } while (0) #define ZEND_TRY_ASSIGN_NULL(zv) \ @@ -1122,8 +1124,10 @@ ZEND_API zend_result zend_try_assign_typed_ref_zval_ex(zend_reference *ref, zval } \ _zv = &ref->val; \ } \ - zval_ptr_dtor(_zv); \ + zval garbage; \ + ZVAL_COPY_VALUE(&garbage, _zv); \ ZVAL_FALSE(_zv); \ + zval_ptr_dtor(&garbage); \ } while (0) #define ZEND_TRY_ASSIGN_FALSE(zv) \ @@ -1144,8 +1148,10 @@ ZEND_API zend_result zend_try_assign_typed_ref_zval_ex(zend_reference *ref, zval } \ _zv = &ref->val; \ } \ - zval_ptr_dtor(_zv); \ + zval garbage; \ + ZVAL_COPY_VALUE(&garbage, _zv); \ ZVAL_TRUE(_zv); \ + zval_ptr_dtor(&garbage); \ } while (0) #define ZEND_TRY_ASSIGN_TRUE(zv) \ @@ -1166,8 +1172,10 @@ ZEND_API zend_result zend_try_assign_typed_ref_zval_ex(zend_reference *ref, zval } \ _zv = &ref->val; \ } \ - zval_ptr_dtor(_zv); \ + zval garbage; \ + ZVAL_COPY_VALUE(&garbage, _zv); \ ZVAL_BOOL(_zv, bval); \ + zval_ptr_dtor(&garbage); \ } while (0) #define ZEND_TRY_ASSIGN_BOOL(zv, bval) \ @@ -1188,8 +1196,10 @@ ZEND_API zend_result zend_try_assign_typed_ref_zval_ex(zend_reference *ref, zval } \ _zv = &ref->val; \ } \ - zval_ptr_dtor(_zv); \ + zval garbage; \ + ZVAL_COPY_VALUE(&garbage, _zv); \ ZVAL_LONG(_zv, lval); \ + zval_ptr_dtor(&garbage); \ } while (0) #define ZEND_TRY_ASSIGN_LONG(zv, lval) \ @@ -1210,8 +1220,10 @@ ZEND_API zend_result zend_try_assign_typed_ref_zval_ex(zend_reference *ref, zval } \ _zv = &ref->val; \ } \ - zval_ptr_dtor(_zv); \ + zval garbage; \ + ZVAL_COPY_VALUE(&garbage, _zv); \ ZVAL_DOUBLE(_zv, dval); \ + zval_ptr_dtor(&garbage); \ } while (0) #define ZEND_TRY_ASSIGN_DOUBLE(zv, dval) \ @@ -1232,8 +1244,10 @@ ZEND_API zend_result zend_try_assign_typed_ref_zval_ex(zend_reference *ref, zval } \ _zv = &ref->val; \ } \ - zval_ptr_dtor(_zv); \ + zval garbage; \ + ZVAL_COPY_VALUE(&garbage, _zv); \ ZVAL_EMPTY_STRING(_zv); \ + zval_ptr_dtor(&garbage); \ } while (0) #define ZEND_TRY_ASSIGN_EMPTY_STRING(zv) \ @@ -1254,8 +1268,10 @@ ZEND_API zend_result zend_try_assign_typed_ref_zval_ex(zend_reference *ref, zval } \ _zv = &ref->val; \ } \ - zval_ptr_dtor(_zv); \ + zval garbage; \ + ZVAL_COPY_VALUE(&garbage, _zv); \ ZVAL_STR(_zv, str); \ + zval_ptr_dtor(&garbage); \ } while (0) #define ZEND_TRY_ASSIGN_STR(zv, str) \ @@ -1276,8 +1292,10 @@ ZEND_API zend_result zend_try_assign_typed_ref_zval_ex(zend_reference *ref, zval } \ _zv = &ref->val; \ } \ - zval_ptr_dtor(_zv); \ + zval garbage; \ + ZVAL_COPY_VALUE(&garbage, _zv); \ ZVAL_NEW_STR(_zv, str); \ + zval_ptr_dtor(&garbage); \ } while (0) #define ZEND_TRY_ASSIGN_NEW_STR(zv, str) \ @@ -1298,8 +1316,10 @@ ZEND_API zend_result zend_try_assign_typed_ref_zval_ex(zend_reference *ref, zval } \ _zv = &ref->val; \ } \ - zval_ptr_dtor(_zv); \ + zval garbage; \ + ZVAL_COPY_VALUE(&garbage, _zv); \ ZVAL_STRING(_zv, string); \ + zval_ptr_dtor(&garbage); \ } while (0) #define ZEND_TRY_ASSIGN_STRING(zv, string) \ @@ -1320,8 +1340,10 @@ ZEND_API zend_result zend_try_assign_typed_ref_zval_ex(zend_reference *ref, zval } \ _zv = &ref->val; \ } \ - zval_ptr_dtor(_zv); \ + zval garbage; \ + ZVAL_COPY_VALUE(&garbage, _zv); \ ZVAL_STRINGL(_zv, string, len); \ + zval_ptr_dtor(&garbage); \ } while (0) #define ZEND_TRY_ASSIGN_STRINGL(zv, string, len) \ @@ -1342,8 +1364,10 @@ ZEND_API zend_result zend_try_assign_typed_ref_zval_ex(zend_reference *ref, zval } \ _zv = &ref->val; \ } \ - zval_ptr_dtor(_zv); \ + zval garbage; \ + ZVAL_COPY_VALUE(&garbage, _zv); \ ZVAL_ARR(_zv, arr); \ + zval_ptr_dtor(&garbage); \ } while (0) #define ZEND_TRY_ASSIGN_ARR(zv, arr) \ @@ -1364,8 +1388,10 @@ ZEND_API zend_result zend_try_assign_typed_ref_zval_ex(zend_reference *ref, zval } \ _zv = &ref->val; \ } \ - zval_ptr_dtor(_zv); \ + zval garbage; \ + ZVAL_COPY_VALUE(&garbage, _zv); \ ZVAL_RES(_zv, res); \ + zval_ptr_dtor(&garbage); \ } while (0) #define ZEND_TRY_ASSIGN_RES(zv, res) \ @@ -1386,8 +1412,10 @@ ZEND_API zend_result zend_try_assign_typed_ref_zval_ex(zend_reference *ref, zval } \ _zv = &ref->val; \ } \ - zval_ptr_dtor(_zv); \ + zval garbage; \ + ZVAL_COPY_VALUE(&garbage, _zv); \ ZVAL_COPY_VALUE(_zv, other_zv); \ + zval_ptr_dtor(&garbage); \ } while (0) #define ZEND_TRY_ASSIGN_TMP(zv, other_zv) \ @@ -1408,8 +1436,10 @@ ZEND_API zend_result zend_try_assign_typed_ref_zval_ex(zend_reference *ref, zval } \ _zv = &ref->val; \ } \ - zval_ptr_dtor(_zv); \ + zval garbage; \ + ZVAL_COPY_VALUE(&garbage, _zv); \ ZVAL_COPY_VALUE(_zv, other_zv); \ + zval_ptr_dtor(&garbage); \ } while (0) #define ZEND_TRY_ASSIGN_VALUE(zv, other_zv) \ @@ -1440,8 +1470,10 @@ ZEND_API zend_result zend_try_assign_typed_ref_zval_ex(zend_reference *ref, zval } \ _zv = &ref->val; \ } \ - zval_ptr_dtor(_zv); \ + zval garbage; \ + ZVAL_COPY_VALUE(&garbage, _zv); \ ZVAL_COPY_VALUE(_zv, other_zv); \ + zval_ptr_dtor(&garbage); \ } while (0) #define ZEND_TRY_ASSIGN_VALUE_EX(zv, other_zv, strict) \