From 62bec0e083aee4cba17d459fb4e07e1599772b12 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Tue, 7 Jul 2020 14:22:58 +0200 Subject: [PATCH] Fixed bug #79784 The fix here is essentially the same as for bug #78598, just for the undefined variable notice, rather than the undefined index one. --- NEWS | 2 ++ Zend/tests/bug79784.phpt | 20 ++++++++++++++++++++ Zend/zend_execute.c | 19 ++++++++++++++++--- 3 files changed, 38 insertions(+), 3 deletions(-) create mode 100644 Zend/tests/bug79784.phpt diff --git a/NEWS b/NEWS index 7a0df9806a1..bfe7b596ebf 100644 --- a/NEWS +++ b/NEWS @@ -21,6 +21,8 @@ PHP NEWS (Nikita) . Fixed bug #78598 (Changing array during undef index RW error segfaults). (Nikita) + . Fixed bug #79784 (Use after free if changing array during undef var during + array write fetch). (Nikita) - Fileinfo: . Fixed bug #79756 (finfo_file crash (FILEINFO_MIME)). (cmb) diff --git a/Zend/tests/bug79784.phpt b/Zend/tests/bug79784.phpt new file mode 100644 index 00000000000..be1cd729e96 --- /dev/null +++ b/Zend/tests/bug79784.phpt @@ -0,0 +1,20 @@ +--TEST-- +Bug #79784: Use after free if changing array during undef var during array write fetch +--FILE-- + +--EXPECT-- +NULL +NULL +NULL diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 7b27c5a3a50..5aed92ff452 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -2067,12 +2067,25 @@ static ZEND_COLD void zend_binary_assign_op_dim_slow(zval *container, zval *dim FREE_OP(free_op_data1); } -static zend_never_inline zend_uchar slow_index_convert(const zval *dim, zend_value *value EXECUTE_DATA_DC) +static zend_never_inline zend_uchar slow_index_convert(HashTable *ht, const zval *dim, zend_value *value EXECUTE_DATA_DC) { switch (Z_TYPE_P(dim)) { - case IS_UNDEF: + case IS_UNDEF: { + /* The array may be destroyed while throwing the notice. + * Temporarily increase the refcount to detect this situation. */ + if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) { + GC_ADDREF(ht); + } ZVAL_UNDEFINED_OP2(); + if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) && !GC_DELREF(ht)) { + zend_array_destroy(ht); + return IS_NULL; + } + if (EG(exception)) { + return IS_NULL; + } /* break missing intentionally */ + } case IS_NULL: value->str = ZSTR_EMPTY_ALLOC(); return IS_STRING; @@ -2182,7 +2195,7 @@ str_index: goto try_again; } else { zend_value val; - zend_uchar t = slow_index_convert(dim, &val EXECUTE_DATA_CC); + zend_uchar t = slow_index_convert(ht, dim, &val EXECUTE_DATA_CC); if (t == IS_STRING) { offset_key = val.str;