From 2fbec0974fd6ec89555f37356a8376f680b9bf49 Mon Sep 17 00:00:00 2001 From: George Peter Banyard Date: Mon, 24 Jul 2023 16:15:57 +0100 Subject: [PATCH] Fix OSS Fuzz #60734: use-after-free visible in ASAN build --- .../in-de-crement/object_cannot_incdec.phpt | 45 +++++++++++++++++++ .../object_cannot_incdec_use_result_op.phpt | 45 +++++++++++++++++++ .../oss-fuzz-60734_predec-object.phpt | 14 ++++++ .../oss-fuzz-60734_preinc-object.phpt | 14 ++++++ Zend/zend_vm_def.h | 8 ++++ Zend/zend_vm_execute.h | 16 +++++++ 6 files changed, 142 insertions(+) create mode 100644 Zend/tests/in-de-crement/object_cannot_incdec.phpt create mode 100644 Zend/tests/in-de-crement/object_cannot_incdec_use_result_op.phpt create mode 100644 Zend/tests/in-de-crement/oss-fuzz-60734_predec-object.phpt create mode 100644 Zend/tests/in-de-crement/oss-fuzz-60734_preinc-object.phpt diff --git a/Zend/tests/in-de-crement/object_cannot_incdec.phpt b/Zend/tests/in-de-crement/object_cannot_incdec.phpt new file mode 100644 index 00000000000..39a41d61dd3 --- /dev/null +++ b/Zend/tests/in-de-crement/object_cannot_incdec.phpt @@ -0,0 +1,45 @@ +--TEST-- +Cannot increment/decrement objects +--FILE-- +getMessage(), PHP_EOL; + var_dump($o); +} +try { + $o--; +} catch (\TypeError $e) { + echo $e->getMessage(), PHP_EOL; + var_dump($o); +} +try { + ++$o; +} catch (\TypeError $e) { + echo $e->getMessage(), PHP_EOL; + var_dump($o); +} +try { + --$o; +} catch (\TypeError $e) { + echo $e->getMessage(), PHP_EOL; + var_dump($o); +} +?> +--EXPECT-- +Cannot increment Foo +object(Foo)#1 (0) { +} +Cannot decrement Foo +object(Foo)#1 (0) { +} +Cannot increment Foo +object(Foo)#1 (0) { +} +Cannot decrement Foo +object(Foo)#1 (0) { +} diff --git a/Zend/tests/in-de-crement/object_cannot_incdec_use_result_op.phpt b/Zend/tests/in-de-crement/object_cannot_incdec_use_result_op.phpt new file mode 100644 index 00000000000..b4c193a6718 --- /dev/null +++ b/Zend/tests/in-de-crement/object_cannot_incdec_use_result_op.phpt @@ -0,0 +1,45 @@ +--TEST-- +Cannot increment/decrement objects +--FILE-- +getMessage(), PHP_EOL; + var_dump($o); +} +try { + $y = $o--; +} catch (\TypeError $e) { + echo $e->getMessage(), PHP_EOL; + var_dump($o); +} +try { + $y = ++$o; +} catch (\TypeError $e) { + echo $e->getMessage(), PHP_EOL; + var_dump($o); +} +try { + $y = --$o; +} catch (\TypeError $e) { + echo $e->getMessage(), PHP_EOL; + var_dump($o); +} +?> +--EXPECT-- +Cannot increment Foo +object(Foo)#1 (0) { +} +Cannot decrement Foo +object(Foo)#1 (0) { +} +Cannot increment Foo +object(Foo)#1 (0) { +} +Cannot decrement Foo +object(Foo)#1 (0) { +} diff --git a/Zend/tests/in-de-crement/oss-fuzz-60734_predec-object.phpt b/Zend/tests/in-de-crement/oss-fuzz-60734_predec-object.phpt new file mode 100644 index 00000000000..0f0e19c8c2d --- /dev/null +++ b/Zend/tests/in-de-crement/oss-fuzz-60734_predec-object.phpt @@ -0,0 +1,14 @@ +--TEST-- +OSS Fuzz #60734: use-after-free visible in ASAN build pre decrement. +--FILE-- + +--EXPECTF-- +Fatal error: Uncaught TypeError: Cannot decrement Foo in %s:%d +Stack trace: +#0 {main} + thrown in %s on line %d diff --git a/Zend/tests/in-de-crement/oss-fuzz-60734_preinc-object.phpt b/Zend/tests/in-de-crement/oss-fuzz-60734_preinc-object.phpt new file mode 100644 index 00000000000..3bae551f04f --- /dev/null +++ b/Zend/tests/in-de-crement/oss-fuzz-60734_preinc-object.phpt @@ -0,0 +1,14 @@ +--TEST-- +OSS Fuzz #60734: use-after-free visible in ASAN build pre increment. +--FILE-- + +--EXPECTF-- +Fatal error: Uncaught TypeError: Cannot increment Foo in %s:%d +Stack trace: +#0 {main} + thrown in %s on line %d diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index b2e3e60a294..1a950590200 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -1501,6 +1501,10 @@ ZEND_VM_HELPER(zend_pre_inc_helper, VAR|CV, ANY) } increment_function(var_ptr); if (UNEXPECTED(EG(exception))) { + /* Smart branch expects result to be set with exceptions */ + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_NULL(EX_VAR(opline->result.var)); + } HANDLE_EXCEPTION(); } } while (0); @@ -1556,6 +1560,10 @@ ZEND_VM_HELPER(zend_pre_dec_helper, VAR|CV, ANY) } decrement_function(var_ptr); if (UNEXPECTED(EG(exception))) { + /* Smart branch expects result to be set with exceptions */ + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_NULL(EX_VAR(opline->result.var)); + } HANDLE_EXCEPTION(); } } while (0); diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 1db9b06a178..881dec2d9d3 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -21625,6 +21625,10 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_pre_inc_help } increment_function(var_ptr); if (UNEXPECTED(EG(exception))) { + /* Smart branch expects result to be set with exceptions */ + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_NULL(EX_VAR(opline->result.var)); + } HANDLE_EXCEPTION(); } } while (0); @@ -21698,6 +21702,10 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_pre_dec_help } decrement_function(var_ptr); if (UNEXPECTED(EG(exception))) { + /* Smart branch expects result to be set with exceptions */ + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_NULL(EX_VAR(opline->result.var)); + } HANDLE_EXCEPTION(); } } while (0); @@ -39000,6 +39008,10 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_pre_inc_help } increment_function(var_ptr); if (UNEXPECTED(EG(exception))) { + /* Smart branch expects result to be set with exceptions */ + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_NULL(EX_VAR(opline->result.var)); + } HANDLE_EXCEPTION(); } } while (0); @@ -39072,6 +39084,10 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_pre_dec_help } decrement_function(var_ptr); if (UNEXPECTED(EG(exception))) { + /* Smart branch expects result to be set with exceptions */ + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_NULL(EX_VAR(opline->result.var)); + } HANDLE_EXCEPTION(); } } while (0);