Bug #80663 [Ver->Csd]: Recursive SplFixedArray::setSize() may cause double-free
| From: | git@php.net | Date: | Tue, 28 Sep 2021 13:56:50 +0000 |
| Subject: | Bug #80663 [Ver->Csd]: Recursive SplFixedArray::setSize() may cause double-free | ||
| References: | 1 | Groups: | php.bugs |
| Request: | Send a blank email to php-bugs+get-236894@lists.php.net to get a copy of this message | ||
Edit report at https://bugs.php.net/bug.php?id=80663&edit=1
ID: 80663
Updated by: git@php.net
Reported by: tandre@php.net
Summary: Recursive SplFixedArray::setSize() may cause
double-free
-Status: Verified
+Status: Closed
Type: Bug
Package: SPL related
Operating System: Linux(any?)
PHP Version: 7.3.26
Assigned To: cmb
Block user comment: N
Private report: N
New Comment:
Automatic comment on behalf of cmb69
Revision: https://github.com/php/php-src/commit/2d6684091fc365df01905be51d906655385da3ba
Log: Fix #80663: Recursive SplFixedArray::setSize() may cause double-free
Previous Comments:
------------------------------------------------------------------------
[2021-09-20 14:34:55] cmb@php.net
The following pull request has been associated:
Patch Name: Fix #80663: Recursive SplFixedArray::setSize() may cause double-free
On GitHub: https://github.com/php/php-src/pull/7503
Patch: https://github.com/php/php-src/pull/7503.patch
------------------------------------------------------------------------
[2021-09-10 13:43:14] cmb@php.net
The following pull request has been associated:
Patch Name: Fix #80663: Recursive SplFixedArray::setSize() may cause double-free
On GitHub: https://github.com/php/php-src/pull/7485
Patch: https://github.com/php/php-src/pull/7485.patch
------------------------------------------------------------------------
[2021-01-23 21:57:15] tandre@php.net
Description:
------------
I noticed when looking at spl classes that SplFixedArray (and probably SplObjectStorage for
emalloced key-value entries) doesn't check if the underlying storage is freed in the middle of
resizing, i.e. there are missing checks for re-entry due to __destruct being called.
It might be possible to fix those warnings by allocating a temporary buffer as a local variable,
copying the range of zvals that need to be released, then calling those destructors. Or by
explicitly forbidding resizing while modifying
Calling this a security bug may be excessive : In realistic applications, (it's probably the
case that) nobody would write code like this and there might be other known issues, but it may be
worse when combined with unserialize() issues or if buggy libraries using SplFixedArray are
identified.
__set_state would have the same issue in zval_ptr_dtor_range (e.g. if an error handler triggered a
call to setSize())
e.g. calling SplObjectStorage->detach() from __destruct when updating an existing
SplObjectStorage entry may cause use after free, I haven't checked.
Mentioned in https://github.com/php/php-src/pull/6261
Test script:
---------------
<?php
// errors are reported with USE_ZEND_ALLOC=0 valgrind php, tested with 7.3, 7.4 and 8.0
class InvalidDestructor {
public function __destruct() {
$GLOBALS['obj']->setSize(0);
}
}
$obj = new SplFixedArray(1000);
$obj[0] = new InvalidDestructor();
$obj->setSize(0);
Expected result:
----------------
No valgrind errors for double free or invalid memory accesses
Actual result:
--------------
```
...other valgrind spl errors
==99097== Invalid read of size 1
==99097== at 0x7A40E4: zval_ptr_dtor (in /path/to/php-8.0.1-nts-install/bin/php)
==99097== by 0x664023: zim_SplFixedArray_setSize (in /path/to/php-8.0.1-nts-install/bin/php)
==99097== by 0x817557: execute_ex (in /path/to/php-8.0.1-nts-install/bin/php)
==99097== by 0x817A59: zend_execute (in /path/to/php-8.0.1-nts-install/bin/php)
==99097== by 0x7A6EFB: zend_execute_scripts (in /path/to/php-8.0.1-nts-install/bin/php)
==99097== by 0x732B51: php_execute_script (in /path/to/php-8.0.1-nts-install/bin/php)
==99097== by 0x8425DF: do_cli (in /path/to/php-8.0.1-nts-install/bin/php)
==99097== by 0x363D91: main (in /path/to/php-8.0.1-nts-install/bin/php)
==99097== Address 0x949c0d9 is 25 bytes inside a block of size 16,000 free'd
==99097== at 0x483CA3F: free (in
/usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==99097== by 0x664034: zim_SplFixedArray_setSize (in /path/to/php-8.0.1-nts-install/bin/php)
==99097== by 0x817557: execute_ex (in /path/to/php-8.0.1-nts-install/bin/php)
==99097== by 0x7969E7: zend_call_function (in /path/to/php-8.0.1-nts-install/bin/php)
==99097== by 0x796E4A: zend_call_known_function (in /path/to/php-8.0.1-nts-install/bin/php)
==99097== by 0x835BB3: zend_objects_destroy_object (in /path/to/php-8.0.1-nts-install/bin/php)
==99097== by 0x83A672: zend_objects_store_del (in /path/to/php-8.0.1-nts-install/bin/php)
==99097== by 0x664023: zim_SplFixedArray_setSize (in /path/to/php-8.0.1-nts-install/bin/php)
==99097== by 0x817557: execute_ex (in /path/to/php-8.0.1-nts-install/bin/php)
==99097== by 0x817A59: zend_execute (in /path/to/php-8.0.1-nts-install/bin/php)
==99097== by 0x7A6EFB: zend_execute_scripts (in /path/to/php-8.0.1-nts-install/bin/php)
==99097== by 0x732B51: php_execute_script (in /path/to/php-8.0.1-nts-install/bin/php)
==99097== Block was alloc'd at
==99097== at 0x483B7F3: malloc (in
/usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==99097== by 0x76FF4C: __zend_malloc (in /path/to/php-8.0.1-nts-install/bin/php)
==99097== by 0x663E1B: zim_SplFixedArray___construct (in /path/to/php-8.0.1-nts-install/bin/php)
==99097== by 0x817557: execute_ex (in /path/to/php-8.0.1-nts-install/bin/php)
==99097== by 0x817A59: zend_execute (in /path/to/php-8.0.1-nts-install/bin/php)
==99097== by 0x7A6EFB: zend_execute_scripts (in /path/to/php-8.0.1-nts-install/bin/php)
==99097== by 0x732B51: php_execute_script (in /path/to/php-8.0.1-nts-install/bin/php)
==99097== by 0x8425DF: do_cli (in /path/to/php-8.0.1-nts-install/bin/php)
==99097== by 0x363D91: main (in /path/to/php-8.0.1-nts-install/bin/php)
```
------------------------------------------------------------------------
--
Edit this bug report at https://bugs.php.net/bug.php?id=80663&edit=1