From 0a193e8d9f457f98b5d4e78ffbc754834ee6b73a Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Thu, 16 Jan 2025 13:30:25 +0000 Subject: [PATCH 1/2] ext/standard: Add some callback unserialization tests --- ...zation_objects_callback_lc_conversion.phpt | 20 +++++++++++++++++++ ...zation_objects_callback_non_existent.phpt} | 0 ...ialization_objects_callback_null_byte.phpt | 19 ++++++++++++++++++ 3 files changed, 39 insertions(+) create mode 100644 ext/standard/tests/serialize/serialization_objects_callback_lc_conversion.phpt rename ext/standard/tests/serialize/{serialization_objects_008.phpt => serialization_objects_callback_non_existent.phpt} (100%) create mode 100644 ext/standard/tests/serialize/serialization_objects_callback_null_byte.phpt diff --git a/ext/standard/tests/serialize/serialization_objects_callback_lc_conversion.phpt b/ext/standard/tests/serialize/serialization_objects_callback_lc_conversion.phpt new file mode 100644 index 0000000000000..6659510024653 --- /dev/null +++ b/ext/standard/tests/serialize/serialization_objects_callback_lc_conversion.phpt @@ -0,0 +1,20 @@ +--TEST-- +Bad unserialize_callback_func +--FILE-- +getMessage(), "\n"; +} +?> +--EXPECTF-- +string(3) "FOO" + +Warning: unserialize(): Function PascalCase() hasn't defined the class it was called for in %s on line %d diff --git a/ext/standard/tests/serialize/serialization_objects_008.phpt b/ext/standard/tests/serialize/serialization_objects_callback_non_existent.phpt similarity index 100% rename from ext/standard/tests/serialize/serialization_objects_008.phpt rename to ext/standard/tests/serialize/serialization_objects_callback_non_existent.phpt diff --git a/ext/standard/tests/serialize/serialization_objects_callback_null_byte.phpt b/ext/standard/tests/serialize/serialization_objects_callback_null_byte.phpt new file mode 100644 index 0000000000000..9e18b30210180 --- /dev/null +++ b/ext/standard/tests/serialize/serialization_objects_callback_null_byte.phpt @@ -0,0 +1,19 @@ +--TEST-- +unserialize_callback_func which contains null bytes +--FILE-- +getMessage(), "\n"; +} +?> +--EXPECTF-- +Haha +Warning: unserialize(): Function foo() hasn't defined the class it was called for in %s on line %d From 280ac48e9f8e5ea110bf2fcad56c89f43c92f64e Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Thu, 16 Jan 2025 13:24:20 +0000 Subject: [PATCH 2/2] ext/standard: Refactor unserialization callback function call This also stores the callback function name as a zend_string --- ...ization_objects_callback_non_existent.phpt | 2 +- ...ialization_objects_callback_null_byte.phpt | 5 ++--- ext/standard/var_unserializer.re | 22 +++++++++---------- main/main.c | 2 +- main/php_globals.h | 2 +- 5 files changed, 16 insertions(+), 17 deletions(-) diff --git a/ext/standard/tests/serialize/serialization_objects_callback_non_existent.phpt b/ext/standard/tests/serialize/serialization_objects_callback_non_existent.phpt index 650ba56330d4a..dce4b659867f6 100644 --- a/ext/standard/tests/serialize/serialization_objects_callback_non_existent.phpt +++ b/ext/standard/tests/serialize/serialization_objects_callback_non_existent.phpt @@ -10,4 +10,4 @@ try { } ?> --EXPECT-- -Invalid callback Nonexistent, function "Nonexistent" not found or invalid function name +Unserialization function Nonexistent is not defined diff --git a/ext/standard/tests/serialize/serialization_objects_callback_null_byte.phpt b/ext/standard/tests/serialize/serialization_objects_callback_null_byte.phpt index 9e18b30210180..e3ab980813be4 100644 --- a/ext/standard/tests/serialize/serialization_objects_callback_null_byte.phpt +++ b/ext/standard/tests/serialize/serialization_objects_callback_null_byte.phpt @@ -14,6 +14,5 @@ try { echo $e->getMessage(), "\n"; } ?> ---EXPECTF-- -Haha -Warning: unserialize(): Function foo() hasn't defined the class it was called for in %s on line %d +--EXPECT-- +Unserialization function foo is not defined diff --git a/ext/standard/var_unserializer.re b/ext/standard/var_unserializer.re index cbd457e16fdb1..6f8c08133b62b 100644 --- a/ext/standard/var_unserializer.re +++ b/ext/standard/var_unserializer.re @@ -1138,8 +1138,6 @@ object ":" uiv ":" ["] { bool custom_object = 0; bool has_unserialize = 0; - zval user_func; - zval retval; zval args[1]; if (!var_hash) return 0; @@ -1243,37 +1241,39 @@ object ":" uiv ":" ["] { } /* Check for unserialize callback */ - if ((PG(unserialize_callback_func) == NULL) || (PG(unserialize_callback_func)[0] == '\0')) { + if ((PG(unserialize_callback_func) == NULL) || (ZSTR_LEN(PG(unserialize_callback_func)) == 0)) { incomplete_class = 1; ce = PHP_IC_ENTRY; break; } - /* Call unserialize callback */ - ZVAL_STRING(&user_func, PG(unserialize_callback_func)); + /* Find unserialize callback */ + zend_function *callback_fn = zend_hash_find_ptr_lc(EG(function_table), PG(unserialize_callback_func)); + if (callback_fn == NULL) { + zend_string_release_ex(class_name, 0); + zend_throw_error(NULL, "Unserialization function %s is not defined", ZSTR_VAL(PG(unserialize_callback_func))); + return 0; + } + /* Call unserialize callback */ ZVAL_STR(&args[0], class_name); BG(serialize_lock)++; - call_user_function(NULL, NULL, &user_func, &retval, 1, args); + zend_call_known_function(callback_fn, NULL, NULL, NULL, 1, args, NULL); BG(serialize_lock)--; - zval_ptr_dtor(&retval); if (EG(exception)) { zend_string_release_ex(class_name, 0); - zval_ptr_dtor(&user_func); return 0; } /* The callback function may have defined the class */ BG(serialize_lock)++; if ((ce = zend_lookup_class(class_name)) == NULL) { - php_error_docref(NULL, E_WARNING, "Function %s() hasn't defined the class it was called for", Z_STRVAL(user_func)); + php_error_docref(NULL, E_WARNING, "Function %s() hasn't defined the class it was called for", ZSTR_VAL(PG(unserialize_callback_func))); incomplete_class = 1; ce = PHP_IC_ENTRY; } BG(serialize_lock)--; - - zval_ptr_dtor(&user_func); } while (0); *p = YYCURSOR; diff --git a/main/main.c b/main/main.c index 5e95df9ac03bb..a53e8b30f1326 100644 --- a/main/main.c +++ b/main/main.c @@ -759,7 +759,7 @@ PHP_INI_BEGIN() STD_PHP_INI_BOOLEAN("auto_globals_jit", "1", PHP_INI_PERDIR|PHP_INI_SYSTEM, OnUpdateBool, auto_globals_jit, php_core_globals, core_globals) STD_PHP_INI_BOOLEAN("short_open_tag", DEFAULT_SHORT_OPEN_TAG, PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateBool, short_tags, zend_compiler_globals, compiler_globals) - STD_PHP_INI_ENTRY("unserialize_callback_func", NULL, PHP_INI_ALL, OnUpdateString, unserialize_callback_func, php_core_globals, core_globals) + STD_PHP_INI_ENTRY("unserialize_callback_func", NULL, PHP_INI_ALL, OnUpdateStr, unserialize_callback_func, php_core_globals, core_globals) STD_PHP_INI_ENTRY("serialize_precision", "-1", PHP_INI_ALL, OnSetSerializePrecision, serialize_precision, php_core_globals, core_globals) STD_PHP_INI_ENTRY("arg_separator.output", "&", PHP_INI_ALL, OnUpdateStringUnempty, arg_separator.output, php_core_globals, core_globals) STD_PHP_INI_ENTRY("arg_separator.input", "&", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateStringUnempty, arg_separator.input, php_core_globals, core_globals) diff --git a/main/php_globals.h b/main/php_globals.h index b2f2696c2db2c..4e8119effb365 100644 --- a/main/php_globals.h +++ b/main/php_globals.h @@ -68,7 +68,7 @@ struct _php_core_globals { char *output_handler; - char *unserialize_callback_func; + zend_string *unserialize_callback_func; zend_long serialize_precision; zend_long memory_limit;