summaryrefslogtreecommitdiff
path: root/ext
diff options
context:
space:
mode:
authorDmitry Stogov <dmitry@zend.com>2021-02-17 13:30:52 +0300
committerDmitry Stogov <dmitry@zend.com>2021-02-17 13:30:52 +0300
commit76b3635607eb74ebe77e0c03df417cc2ffa6ee99 (patch)
tree8a5655e7dc938e7597a58f36d6555b02f043163b /ext
parent5c78e8739996c9dbedbe024cc1ee9ab0443fa69f (diff)
downloadphp-git-76b3635607eb74ebe77e0c03df417cc2ffa6ee99.tar.gz
unserialize() optimization. Omit class name validation before hash lookup, and perform it only before autoloading.
Diffstat (limited to 'ext')
-rw-r--r--ext/standard/var_unserializer.re54
1 files changed, 40 insertions, 14 deletions
diff --git a/ext/standard/var_unserializer.re b/ext/standard/var_unserializer.re
index dec3d9c081..5f3b81a77d 100644
--- a/ext/standard/var_unserializer.re
+++ b/ext/standard/var_unserializer.re
@@ -342,12 +342,9 @@ static zend_string *unserialize_str(const unsigned char **p, size_t len, size_t
}
static inline int unserialize_allowed_class(
- zend_string *class_name, php_unserialize_data_t *var_hashx)
+ zend_string *lcname, php_unserialize_data_t *var_hashx)
{
HashTable *classes = (*var_hashx)->allowed_classes;
- zend_string *lcname;
- int res;
- ALLOCA_FLAG(use_heap)
if(classes == NULL) {
return 1;
@@ -356,11 +353,7 @@ static inline int unserialize_allowed_class(
return 0;
}
- ZSTR_ALLOCA_ALLOC(lcname, ZSTR_LEN(class_name), use_heap);
- zend_str_tolower_copy(ZSTR_VAL(lcname), ZSTR_VAL(class_name), ZSTR_LEN(class_name));
- res = zend_hash_exists(classes, lcname);
- ZSTR_ALLOCA_FREE(lcname, use_heap);
- return res;
+ return zend_hash_exists(classes, lcname);
}
#define YYFILL(n) do { } while (0)
@@ -1145,22 +1138,55 @@ object ":" uiv ":" ["] {
return 0;
}
- class_name = zend_string_init(str, len, 0);
- if (!zend_is_valid_class_name(class_name)) {
- zend_string_release_ex(class_name, 0);
+ if (len == 0) {
+ /* empty class names are not allowed */
+ return 0;
+ }
+
+ if (str[0] == '\000') {
+ /* runtime definition keys are not allowed */
return 0;
}
+ if (str[0] == '\\') {
+ /* class name can't start from namespace separator */
+ return 0;
+ }
+
+ class_name = zend_string_init(str, len, 0);
+
do {
- if(!unserialize_allowed_class(class_name, var_hash)) {
+ zend_string *lc_name = zend_string_tolower(class_name);
+
+ if(!unserialize_allowed_class(lc_name, var_hash)) {
+ zend_string_release_ex(lc_name, 0);
+ if (!zend_is_valid_class_name(class_name)) {
+ zend_string_release_ex(class_name, 0);
+ return 0;
+ }
incomplete_class = 1;
ce = PHP_IC_ENTRY;
break;
}
+ ce = zend_hash_find_ptr(EG(class_table), lc_name);
+ if (ce
+ && (ce->ce_flags & ZEND_ACC_LINKED)
+ && !(ce->ce_flags & ZEND_ACC_ANON_CLASS)) {
+ zend_string_release_ex(lc_name, 0);
+ break;
+ }
+
+ if (!zend_is_valid_class_name(class_name)) {
+ zend_string_release_ex(lc_name, 0);
+ zend_string_release_ex(class_name, 0);
+ return 0;
+ }
+
/* Try to find class directly */
BG(serialize_lock)++;
- ce = zend_lookup_class(class_name);
+ ce = zend_lookup_class_ex(class_name, lc_name, 0);
+ zend_string_release_ex(lc_name, 0);
if (ce) {
BG(serialize_lock)--;
if (EG(exception)) {