From b666dc97887c8d5648ab435656d61ec41300dd63 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Sat, 21 Dec 2024 19:05:18 +0100 Subject: [PATCH] Fix GH-15833: Segmentation fault (access null pointer) in ext/spl/spl_array.c We're accessing the object properties table directly in spl, but we're not accounting for lazy objects. Upon accessing we should trigger the initialization as spl is doing direct manipulations on the object property table and expects a real object. Closes GH-17235. --- NEWS | 4 ++++ ext/spl/spl_array.c | 25 ++++++++++++++++++++++ ext/spl/tests/gh15833_1.phpt | 22 +++++++++++++++++++ ext/spl/tests/gh15833_2.phpt | 41 ++++++++++++++++++++++++++++++++++++ 4 files changed, 92 insertions(+) create mode 100644 ext/spl/tests/gh15833_1.phpt create mode 100644 ext/spl/tests/gh15833_2.phpt diff --git a/NEWS b/NEWS index cc0824a952a..4e734a6e9c0 100644 --- a/NEWS +++ b/NEWS @@ -46,6 +46,10 @@ PHP NEWS . Fixed bug GH-17330 (SNMP::setSecurity segfault on closed session). (David Carlier) +- SPL: + . Fixed bug GH-15833 (Segmentation fault (access null pointer) in + ext/spl/spl_array.c). (nielsdos) + 02 Jan 2025, PHP 8.4.3 - BcMath: diff --git a/ext/spl/spl_array.c b/ext/spl/spl_array.c index 0acbc986119..db7f4fff9bb 100644 --- a/ext/spl/spl_array.c +++ b/ext/spl/spl_array.c @@ -40,6 +40,7 @@ PHPAPI zend_class_entry *spl_ce_ArrayObject; typedef struct _spl_array_object { zval array; + HashTable *sentinel_array; uint32_t ht_iter; int ar_flags; unsigned char nApplyCount; @@ -74,6 +75,19 @@ static inline HashTable **spl_array_get_hash_table_ptr(spl_array_object* intern) return &Z_ARRVAL(intern->array); } else { zend_object *obj = Z_OBJ(intern->array); + /* Since we're directly playing with the properties table, we shall initialize the lazy object directly. + * If we don't, it's possible to continue working with the wrong object in case we're using a proxy. */ + if (UNEXPECTED(zend_lazy_object_must_init(obj))) { + obj = zend_lazy_object_init(obj); + if (UNEXPECTED(!obj)) { + if (!intern->sentinel_array) { + intern->sentinel_array = zend_new_array(0); + } + return &intern->sentinel_array; + } + } + /* should no longer be lazy */ + ZEND_ASSERT(!zend_lazy_object_must_init(obj)); /* rebuild properties */ zend_std_get_properties_ex(obj); if (GC_REFCOUNT(obj->properties) > 1) { @@ -129,6 +143,10 @@ static void spl_array_object_free_storage(zend_object *object) zend_hash_iterator_del(intern->ht_iter); } + if (UNEXPECTED(intern->sentinel_array)) { + zend_array_release(intern->sentinel_array); + } + zend_object_std_dtor(&intern->std); zval_ptr_dtor(&intern->array); @@ -489,6 +507,9 @@ static void spl_array_write_dimension_ex(int check_inherited, zend_object *objec uint32_t refcount = 0; if (!offset || Z_TYPE_P(offset) == IS_NULL) { ht = spl_array_get_hash_table(intern); + if (UNEXPECTED(ht == intern->sentinel_array)) { + return; + } refcount = spl_array_set_refcount(intern->is_child, ht, 1); zend_hash_next_index_insert(ht, value); @@ -505,6 +526,10 @@ static void spl_array_write_dimension_ex(int check_inherited, zend_object *objec } ht = spl_array_get_hash_table(intern); + if (UNEXPECTED(ht == intern->sentinel_array)) { + spl_hash_key_release(&key); + return; + } refcount = spl_array_set_refcount(intern->is_child, ht, 1); if (key.key) { zend_hash_update_ind(ht, key.key, value); diff --git a/ext/spl/tests/gh15833_1.phpt b/ext/spl/tests/gh15833_1.phpt new file mode 100644 index 00000000000..d658a770e80 --- /dev/null +++ b/ext/spl/tests/gh15833_1.phpt @@ -0,0 +1,22 @@ +--TEST-- +GH-15833 (Segmentation fault (access null pointer) in ext/spl/spl_array.c) +--CREDITS-- +YuanchengJiang +--FILE-- +newLazyProxy(function ($obj) { + $obj = new C(); + return $obj; +}); +$recursiveArrayIterator = new RecursiveArrayIterator($obj); +var_dump($recursiveArrayIterator->current()); +$recursiveArrayIterator->next(); +var_dump($recursiveArrayIterator->current()); +?> +--EXPECT-- +int(1) +NULL diff --git a/ext/spl/tests/gh15833_2.phpt b/ext/spl/tests/gh15833_2.phpt new file mode 100644 index 00000000000..8f30921741f --- /dev/null +++ b/ext/spl/tests/gh15833_2.phpt @@ -0,0 +1,41 @@ +--TEST-- +GH-15833 (Segmentation fault (access null pointer) in ext/spl/spl_array.c) +--CREDITS-- +YuanchengJiang +--FILE-- +newLazyProxy(function ($obj) { + static $counter = 0; + throw new Error('nope ' . ($counter++)); +}); +$recursiveArrayIterator = new RecursiveArrayIterator($obj); +try { + var_dump($recursiveArrayIterator->current()); +} catch (Error $e) { + echo $e->getMessage(), "\n"; +} +try { + var_dump($recursiveArrayIterator->current()); +} catch (Error $e) { + echo $e->getMessage(), "\n"; +} +try { + $recursiveArrayIterator->next(); +} catch (Error $e) { + echo $e->getMessage(), "\n"; +} +try { + var_dump($recursiveArrayIterator->current()); +} catch (Error $e) { + echo $e->getMessage(), "\n"; +} +?> +--EXPECT-- +nope 0 +nope 1 +nope 2 +nope 3