From 8b6595423de1a766a5110b962f5a8fa72c4eb6cb Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Fri, 10 Oct 2025 23:22:54 +0200 Subject: [PATCH 1/3] Fix shm corruption with coercion in options of unserialize() --- .../shm_corruption_coercion_unserialize_options.phpt | 8 ++++++++ ext/standard/var.c | 7 ++++--- 2 files changed, 12 insertions(+), 3 deletions(-) create mode 100644 ext/standard/tests/serialize/shm_corruption_coercion_unserialize_options.phpt diff --git a/ext/standard/tests/serialize/shm_corruption_coercion_unserialize_options.phpt b/ext/standard/tests/serialize/shm_corruption_coercion_unserialize_options.phpt new file mode 100644 index 0000000000000..530171b7bdea6 --- /dev/null +++ b/ext/standard/tests/serialize/shm_corruption_coercion_unserialize_options.phpt @@ -0,0 +1,8 @@ +--TEST-- +Shm corruption with coercion in options of unserialize() +--FILE-- + [0]]); +?> +--EXPECTF-- +Warning: unserialize(): Error at offset 0 of 2 bytes in %s on line %d diff --git a/ext/standard/var.c b/ext/standard/var.c index 795fb366c6013..d1ae076992df2 100644 --- a/ext/standard/var.c +++ b/ext/standard/var.c @@ -1366,13 +1366,14 @@ PHPAPI void php_unserialize_with_options(zval *return_value, const char *buf, co } if(class_hash && Z_TYPE_P(classes) == IS_ARRAY) { zval *entry; - zend_string *lcname; + zend_string *lcname, *tmp_str, *str; ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(classes), entry) { - convert_to_string(entry); - lcname = zend_string_tolower(Z_STR_P(entry)); + str = zval_get_tmp_string(entry, &tmp_str); + lcname = zend_string_tolower(str); zend_hash_add_empty_element(class_hash, lcname); zend_string_release_ex(lcname, 0); + zend_tmp_string_release(tmp_str); } ZEND_HASH_FOREACH_END(); /* Exception during string conversion. */ From 332581eef95d5afc22ef6bb6d76fe461132f0ae6 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Sat, 11 Oct 2025 10:49:47 +0200 Subject: [PATCH 2/3] fixup! lifetime --- ext/standard/var.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ext/standard/var.c b/ext/standard/var.c index d1ae076992df2..a3f2cc47532fb 100644 --- a/ext/standard/var.c +++ b/ext/standard/var.c @@ -1366,14 +1366,14 @@ PHPAPI void php_unserialize_with_options(zval *return_value, const char *buf, co } if(class_hash && Z_TYPE_P(classes) == IS_ARRAY) { zval *entry; - zend_string *lcname, *tmp_str, *str; ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(classes), entry) { - str = zval_get_tmp_string(entry, &tmp_str); - lcname = zend_string_tolower(str); + /* Note: cannot use zval_get_tmp_string() here as we need to keep it in class_hash for longer than this loop. */ + zend_string *str = zval_get_string(entry); + zend_string *lcname = zend_string_tolower(str); zend_hash_add_empty_element(class_hash, lcname); - zend_string_release_ex(lcname, 0); - zend_tmp_string_release(tmp_str); + zend_string_release_ex(lcname, false); + zend_string_release_ex(str, false); } ZEND_HASH_FOREACH_END(); /* Exception during string conversion. */ From e9b1d7a2fdec9044b8868cbf3d36710dabd29fe0 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Mon, 13 Oct 2025 20:53:57 +0200 Subject: [PATCH 3/3] Revert "fixup! lifetime" This reverts commit 332581eef95d5afc22ef6bb6d76fe461132f0ae6. --- ext/standard/var.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ext/standard/var.c b/ext/standard/var.c index a3f2cc47532fb..d1ae076992df2 100644 --- a/ext/standard/var.c +++ b/ext/standard/var.c @@ -1366,14 +1366,14 @@ PHPAPI void php_unserialize_with_options(zval *return_value, const char *buf, co } if(class_hash && Z_TYPE_P(classes) == IS_ARRAY) { zval *entry; + zend_string *lcname, *tmp_str, *str; ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(classes), entry) { - /* Note: cannot use zval_get_tmp_string() here as we need to keep it in class_hash for longer than this loop. */ - zend_string *str = zval_get_string(entry); - zend_string *lcname = zend_string_tolower(str); + str = zval_get_tmp_string(entry, &tmp_str); + lcname = zend_string_tolower(str); zend_hash_add_empty_element(class_hash, lcname); - zend_string_release_ex(lcname, false); - zend_string_release_ex(str, false); + zend_string_release_ex(lcname, 0); + zend_tmp_string_release(tmp_str); } ZEND_HASH_FOREACH_END(); /* Exception during string conversion. */