From 56f2fef1c1bbf4f732c1ce52c5893aa41d9dd790 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Wed, 5 Apr 2023 20:30:58 +0200 Subject: [PATCH] Fix GH-11016: Heap buffer overflow in ZEND_ADD_ARRAY_UNPACK_SPEC_HANDLER Not enough space was reserved for the packed resulting array because of some confusion in the meaning of nr of used slots vs nr of elements. Co-authored-by: Ilija Tovilo --- Zend/tests/gh11016.phpt | 20 ++++++++++++++++++++ Zend/zend_vm_def.h | 2 +- Zend/zend_vm_execute.h | 2 +- 3 files changed, 22 insertions(+), 2 deletions(-) create mode 100644 Zend/tests/gh11016.phpt diff --git a/Zend/tests/gh11016.phpt b/Zend/tests/gh11016.phpt new file mode 100644 index 0000000000000..7946166b176d3 --- /dev/null +++ b/Zend/tests/gh11016.phpt @@ -0,0 +1,20 @@ +--TEST-- +GH-11016 (Heap buffer overflow in ZEND_ADD_ARRAY_UNPACK_SPEC_HANDLER) +--FILE-- + 0, ...[1, 1, 1]]; +print_r($x); +?> +--EXPECT-- +Array +( + [6] => 0 + [7] => 1 + [8] => 1 + [9] => 1 +) diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 7ef8cf1922d1e..88b46a641d079 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -6128,7 +6128,7 @@ ZEND_VM_C_LABEL(add_unpack_again): zval *val; if (HT_IS_PACKED(ht) && (zend_hash_num_elements(result_ht) == 0 || HT_IS_PACKED(result_ht))) { - zend_hash_extend(result_ht, zend_hash_num_elements(result_ht) + zend_hash_num_elements(ht), 1); + zend_hash_extend(result_ht, result_ht->nNumUsed + zend_hash_num_elements(ht), 1); ZEND_HASH_FILL_PACKED(result_ht) { ZEND_HASH_PACKED_FOREACH_VAL(ht, val) { if (UNEXPECTED(Z_ISREF_P(val)) && diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 19149c8c18e87..d44be7760c43a 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -2652,7 +2652,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ADD_ARRAY_UNPACK_SPEC_HANDLER( zval *val; if (HT_IS_PACKED(ht) && (zend_hash_num_elements(result_ht) == 0 || HT_IS_PACKED(result_ht))) { - zend_hash_extend(result_ht, zend_hash_num_elements(result_ht) + zend_hash_num_elements(ht), 1); + zend_hash_extend(result_ht, result_ht->nNumUsed + zend_hash_num_elements(ht), 1); ZEND_HASH_FILL_PACKED(result_ht) { ZEND_HASH_PACKED_FOREACH_VAL(ht, val) { if (UNEXPECTED(Z_ISREF_P(val)) &&