From f6d70e9c7240ae5685acb2fef7d6576b5883c861 Mon Sep 17 00:00:00 2001 From: Tyson Andre Date: Sat, 20 Nov 2021 15:20:52 -0500 Subject: [PATCH] Fix use after free when WeakMap is modified during field write (When a value's destructor triggers a resizing or rehashing of the WeakMap) --- Zend/tests/weakrefs/weakrefs_006.phpt | 116 ++++++++++++++++++++++++++ Zend/zend_weakrefs.c | 6 +- 2 files changed, 121 insertions(+), 1 deletion(-) create mode 100644 Zend/tests/weakrefs/weakrefs_006.phpt diff --git a/Zend/tests/weakrefs/weakrefs_006.phpt b/Zend/tests/weakrefs/weakrefs_006.phpt new file mode 100644 index 0000000000000..a15ab6b542d57 --- /dev/null +++ b/Zend/tests/weakrefs/weakrefs_006.phpt @@ -0,0 +1,116 @@ +--TEST-- +WeakReference overwriting existing value +--FILE-- + +--EXPECT-- +In destruct +object(WeakMap)#1 (11) { + [0]=> + array(2) { + ["key"]=> + object(stdClass)#2 (0) { + } + ["value"]=> + int(123) + } + [1]=> + array(2) { + ["key"]=> + object(stdClass)#4 (0) { + } + ["value"]=> + int(0) + } + [2]=> + array(2) { + ["key"]=> + object(stdClass)#5 (0) { + } + ["value"]=> + int(1) + } + [3]=> + array(2) { + ["key"]=> + object(stdClass)#6 (0) { + } + ["value"]=> + int(2) + } + [4]=> + array(2) { + ["key"]=> + object(stdClass)#7 (0) { + } + ["value"]=> + int(3) + } + [5]=> + array(2) { + ["key"]=> + object(stdClass)#8 (0) { + } + ["value"]=> + int(4) + } + [6]=> + array(2) { + ["key"]=> + object(stdClass)#9 (0) { + } + ["value"]=> + int(5) + } + [7]=> + array(2) { + ["key"]=> + object(stdClass)#10 (0) { + } + ["value"]=> + int(6) + } + [8]=> + array(2) { + ["key"]=> + object(stdClass)#11 (0) { + } + ["value"]=> + int(7) + } + [9]=> + array(2) { + ["key"]=> + object(stdClass)#12 (0) { + } + ["value"]=> + int(8) + } + [10]=> + array(2) { + ["key"]=> + object(stdClass)#13 (0) { + } + ["value"]=> + int(9) + } +} \ No newline at end of file diff --git a/Zend/zend_weakrefs.c b/Zend/zend_weakrefs.c index 563097500abfd..1e1efda92391a 100644 --- a/Zend/zend_weakrefs.c +++ b/Zend/zend_weakrefs.c @@ -351,8 +351,12 @@ static void zend_weakmap_write_dimension(zend_object *object, zval *offset, zval zval *zv = zend_hash_index_find(&wm->ht, (zend_ulong) obj_key); if (zv) { - zval_ptr_dtor(zv); + /* Because the destructors can have side effects such as resizing or rehashing the WeakMap storage, + * free the zval only after overwriting the original value. */ + zval zv_orig; + ZVAL_COPY_VALUE(&zv_orig, zv); ZVAL_COPY_VALUE(zv, value); + zval_ptr_dtor(&zv_orig); return; }