-
Notifications
You must be signed in to change notification settings - Fork 7.9k
Heap buffer overflow in ZEND_ADD_ARRAY_UNPACK_SPEC_HANDLER #11016
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Very slightly simplified reproducer: <?php
$x = [6.5 => 0, ...[1, 1, 1]]; Note: The floating point key is important to make it overflow, and the length of the nested list must be at least 3. |
My gut feeling says this is the right approach, but I would need to read more about the hashtables to know for sure. diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h
index 7ef8cf1922..b085a30f67 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 + ht->nNumUsed, 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 19149c8c18..bbba8b6da5 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 + ht->nNumUsed, 1);
ZEND_HASH_FILL_PACKED(result_ht) {
ZEND_HASH_PACKED_FOREACH_VAL(ht, val) {
if (UNEXPECTED(Z_ISREF_P(val)) &&
|
I think you're right for |
Makes sense to me. |
…ANDLER 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.
…ANDLER 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 <[email protected]>
…ANDLER 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 <[email protected]>
After a hash filling routine the number of elements are set to the fill index. However, if the fill index is larger than the number of elements, the number of elements are no longer correct. This is observable at least via count() and var_dump(). E.g. the attached test case would incorrectly show int(17) instead of int(11). Solve this by only increasing the number of elements by the actual number that got added. Instead of adding a variable that increments per iteration, I wanted to save some cycles in the iteration and simply compute the number of added elements at the end. I removed the assignment in ZEND_HASH_FILL_GROW() because the number of elements is set anyway at the end of the hash function and this avoids an unnecessary computation. I discovered this behaviour while fixing phpGH-11016, where this filling routine is easily exposed to userland via a specialised VM path [1]. Since this seems to be more a general problem with the macros, and may be triggered outside of the VM handlers, I fixed it in the macros instead of modifying the VM to fixup the number of elements. [1] https://github.com/php/php-src/blob/b2c5acbb010f4bbc7ea9b53ba9bc81d672dd0f34/Zend/zend_vm_def.h#L6132-L6141
I think, the proper fix in conjunction with #9796 should be zend_hash_extend(result_ht, result_ht->nNumUsed + zend_hash_num_elements(ht), 1); |
After a hash filling routine the number of elements are set to the fill index. However, if the fill index is larger than the number of elements, the number of elements are no longer correct. This is observable at least via count() and var_dump(). E.g. the attached test case would incorrectly show int(17) instead of int(11). Solve this by only increasing the number of elements by the actual number that got added. Instead of adding a variable that increments per iteration, I wanted to save some cycles in the iteration and simply compute the number of added elements at the end. I discovered this behaviour while fixing phpGH-11016, where this filling routine is easily exposed to userland via a specialised VM path [1]. Since this seems to be more a general problem with the macros, and may be triggered outside of the VM handlers, I fixed it in the macros instead of modifying the VM to fixup the number of elements. [1] https://github.com/php/php-src/blob/b2c5acbb010f4bbc7ea9b53ba9bc81d672dd0f34/Zend/zend_vm_def.h#L6132-L6141
After a hash filling routine the number of elements are set to the fill index. However, if the fill index is larger than the number of elements, the number of elements are no longer correct. This is observable at least via count() and var_dump(). E.g. the attached test case would incorrectly show int(17) instead of int(11). Solve this by only increasing the number of elements by the actual number that got added. Instead of adding a variable that increments per iteration, I wanted to save some cycles in the iteration and simply compute the number of added elements at the end. I discovered this behaviour while fixing GH-11016, where this filling routine is easily exposed to userland via a specialised VM path [1]. Since this seems to be more a general problem with the macros, and may be triggered outside of the VM handlers, I fixed it in the macros instead of modifying the VM to fixup the number of elements. [1] https://github.com/php/php-src/blob/b2c5acbb010f4bbc7ea9b53ba9bc81d672dd0f34/Zend/zend_vm_def.h#L6132-L6141
…LER (#11021) 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 <[email protected]>
Description
The following code:
Using the asan build and
USE_TRACKED_ALLOC=1 USE_ZEND_ALLOC=0 php-src/asan/sapi/cli/php -f poc1.php
Resulted in this output:
But I expected this output instead:
PHP Version
PHP 8.3.0-dev
Operating System
No response
The text was updated successfully, but these errors were encountered: