From 6c8ec685b8ce9f5a2ac8a85ecb4a186083da1c30 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Sun, 18 May 2025 14:30:35 +0200 Subject: [PATCH] Fix OSS-Fuzz #417078295 If the variable_ptr and fetched value are the same or overlap, then we get a UAF. Prevent this by delaying destruction. --- Zend/tests/oss_fuzz_417078295.phpt | 17 +++++++++++++++++ Zend/zend_vm_def.h | 3 ++- Zend/zend_vm_execute.h | 3 ++- 3 files changed, 21 insertions(+), 2 deletions(-) create mode 100644 Zend/tests/oss_fuzz_417078295.phpt diff --git a/Zend/tests/oss_fuzz_417078295.phpt b/Zend/tests/oss_fuzz_417078295.phpt new file mode 100644 index 0000000000000..6e53f9478e137 --- /dev/null +++ b/Zend/tests/oss_fuzz_417078295.phpt @@ -0,0 +1,17 @@ +--TEST-- +OSS-Fuzz #417078295 +--FILE-- + +--EXPECT-- +object(stdClass)#1 (0) refcount(2){ +} diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 53aa7a821f697..74182f98dff37 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -8980,7 +8980,6 @@ ZEND_VM_HANDLER(183, ZEND_BIND_STATIC, CV, ANY, REF) value = (zval*)((char*)ht->arData + (opline->extended_value & ~(ZEND_BIND_REF|ZEND_BIND_IMPLICIT|ZEND_BIND_EXPLICIT))); if (opline->extended_value & ZEND_BIND_REF) { - i_zval_ptr_dtor(variable_ptr); if (UNEXPECTED(!Z_ISREF_P(value))) { zend_reference *ref = (zend_reference*)emalloc(sizeof(zend_reference)); GC_SET_REFCOUNT(ref, 2); @@ -8995,9 +8994,11 @@ ZEND_VM_HANDLER(183, ZEND_BIND_STATIC, CV, ANY, REF) ref->sources.ptr = NULL; Z_REF_P(value) = ref; Z_TYPE_INFO_P(value) = IS_REFERENCE_EX; + i_zval_ptr_dtor(variable_ptr); ZVAL_REF(variable_ptr, ref); } else { Z_ADDREF_P(value); + i_zval_ptr_dtor(variable_ptr); ZVAL_REF(variable_ptr, Z_REF_P(value)); if (OP2_TYPE != IS_UNUSED) { FREE_OP2(); diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 2c86a94134c08..5dfe89015a7c8 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -40548,7 +40548,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_BIND_STATIC_SPEC_CV_HANDLER(ZE value = (zval*)((char*)ht->arData + (opline->extended_value & ~(ZEND_BIND_REF|ZEND_BIND_IMPLICIT|ZEND_BIND_EXPLICIT))); if (opline->extended_value & ZEND_BIND_REF) { - i_zval_ptr_dtor(variable_ptr); if (UNEXPECTED(!Z_ISREF_P(value))) { zend_reference *ref = (zend_reference*)emalloc(sizeof(zend_reference)); GC_SET_REFCOUNT(ref, 2); @@ -40563,9 +40562,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_BIND_STATIC_SPEC_CV_HANDLER(ZE ref->sources.ptr = NULL; Z_REF_P(value) = ref; Z_TYPE_INFO_P(value) = IS_REFERENCE_EX; + i_zval_ptr_dtor(variable_ptr); ZVAL_REF(variable_ptr, ref); } else { Z_ADDREF_P(value); + i_zval_ptr_dtor(variable_ptr); ZVAL_REF(variable_ptr, Z_REF_P(value)); if (opline->op2_type != IS_UNUSED) { FREE_OP(opline->op2_type, opline->op2.var);