From 700d456ee6627154601edbc05a911eeff8731091 Mon Sep 17 00:00:00 2001 From: Stanislav Malyshev Date: Fri, 29 Mar 2013 21:52:48 -0700 Subject: [PATCH] secured unserialize - update for BC-compatible unserialize - add tests --- ext/standard/php_var.h | 1 + .../serialize/serialization_error_001.phpt | 6 +- .../tests/serialize/unserialize_classes.phpt | 88 ++++++++++++++ ext/standard/var.c | 36 +++++- ext/standard/var_unserializer.c | 111 ++++++++++++------ ext/standard/var_unserializer.re | 44 ++++++- 6 files changed, 237 insertions(+), 49 deletions(-) create mode 100644 ext/standard/tests/serialize/unserialize_classes.phpt diff --git a/ext/standard/php_var.h b/ext/standard/php_var.h index 23225cdc42a8d..a4df8f51f9b88 100644 --- a/ext/standard/php_var.h +++ b/ext/standard/php_var.h @@ -57,6 +57,7 @@ PHPAPI void php_var_serialize(smart_str *buf, zval *struc, php_serialize_data_t PHPAPI int php_var_unserialize(zval *rval, const unsigned char **p, const unsigned char *max, php_unserialize_data_t *var_hash TSRMLS_DC); PHPAPI int php_var_unserialize_ref(zval *rval, const unsigned char **p, const unsigned char *max, php_unserialize_data_t *var_hash TSRMLS_DC); PHPAPI int php_var_unserialize_intern(zval *rval, const unsigned char **p, const unsigned char *max, php_unserialize_data_t *var_hash TSRMLS_DC); +PHPAPI int php_var_unserialize_ex(zval *rval, const unsigned char **p, const unsigned char *max, php_unserialize_data_t *var_hash, HashTable *classes TSRMLS_DC); #define PHP_VAR_SERIALIZE_INIT(d) \ do { \ diff --git a/ext/standard/tests/serialize/serialization_error_001.phpt b/ext/standard/tests/serialize/serialization_error_001.phpt index da6f50cc02b29..014128b19f51a 100644 --- a/ext/standard/tests/serialize/serialization_error_001.phpt +++ b/ext/standard/tests/serialize/serialization_error_001.phpt @@ -21,7 +21,7 @@ var_dump( unserialize() ); //Test serialize with one more than the expected number of arguments var_dump( serialize(1,2) ); -var_dump( unserialize(1,2) ); +var_dump( unserialize(1,2,3) ); echo "Done"; ?> @@ -31,12 +31,12 @@ echo "Done"; Warning: serialize() expects exactly 1 parameter, 0 given in %s on line 16 NULL -Warning: unserialize() expects exactly 1 parameter, 0 given in %s on line 17 +Warning: unserialize() expects at least 1 parameter, 0 given in %s on line 17 bool(false) Warning: serialize() expects exactly 1 parameter, 2 given in %s on line 20 NULL -Warning: unserialize() expects exactly 1 parameter, 2 given in %s on line 21 +Warning: unserialize() expects at most 2 parameters, 3 given in %s on line 21 bool(false) Done diff --git a/ext/standard/tests/serialize/unserialize_classes.phpt b/ext/standard/tests/serialize/unserialize_classes.phpt new file mode 100644 index 0000000000000..2a9d8a743c95e --- /dev/null +++ b/ext/standard/tests/serialize/unserialize_classes.phpt @@ -0,0 +1,88 @@ +--TEST-- +Test unserialize() with second parameter +--FILE-- + false])); +var_dump(unserialize($s, ["allowed_classes" => true])); +var_dump(unserialize($s, ["allowed_classes" => ["bar"]])); +var_dump(unserialize($s, ["allowed_classes" => ["FOO"]])); +var_dump(unserialize($s, ["allowed_classes" => ["bar", "foO"]])); + +--EXPECTF-- +array(3) { + [0]=> + object(foo)#%d (1) { + ["x"]=> + string(3) "bar" + } + [1]=> + int(2) + [2]=> + string(1) "3" +} +array(3) { + [0]=> + object(__PHP_Incomplete_Class)#%d (2) { + ["__PHP_Incomplete_Class_Name"]=> + string(3) "foo" + ["x"]=> + string(3) "bar" + } + [1]=> + int(2) + [2]=> + string(1) "3" +} +array(3) { + [0]=> + object(foo)#%d (1) { + ["x"]=> + string(3) "bar" + } + [1]=> + int(2) + [2]=> + string(1) "3" +} +array(3) { + [0]=> + object(__PHP_Incomplete_Class)#%d (2) { + ["__PHP_Incomplete_Class_Name"]=> + string(3) "foo" + ["x"]=> + string(3) "bar" + } + [1]=> + int(2) + [2]=> + string(1) "3" +} +array(3) { + [0]=> + object(foo)#%d (1) { + ["x"]=> + string(3) "bar" + } + [1]=> + int(2) + [2]=> + string(1) "3" +} +array(3) { + [0]=> + object(foo)#%d (1) { + ["x"]=> + string(3) "bar" + } + [1]=> + int(2) + [2]=> + string(1) "3" +} diff --git a/ext/standard/var.c b/ext/standard/var.c index 4f0bd24bdc9f4..24bdd385a5c59 100644 --- a/ext/standard/var.c +++ b/ext/standard/var.c @@ -990,7 +990,7 @@ PHP_FUNCTION(serialize) } /* }}} */ -/* {{{ proto mixed unserialize(string variable_representation) +/* {{{ proto mixed unserialize(string variable_representation[, bool|array allowed_classes]) Takes a string representation of variable and recreates it */ PHP_FUNCTION(unserialize) { @@ -998,8 +998,10 @@ PHP_FUNCTION(unserialize) size_t buf_len; const unsigned char *p; php_unserialize_data_t var_hash; + zval *options = NULL, *classes = NULL; + HashTable *class_hash = NULL; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &buf, &buf_len) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|a", &buf, &buf_len, &options) == FAILURE) { RETURN_FALSE; } @@ -1009,8 +1011,32 @@ PHP_FUNCTION(unserialize) p = (const unsigned char*) buf; PHP_VAR_UNSERIALIZE_INIT(var_hash); - if (!php_var_unserialize(return_value, &p, p + buf_len, &var_hash TSRMLS_CC)) { + if(options != NULL) { + classes = zend_hash_str_find(Z_ARRVAL_P(options), "allowed_classes", sizeof("allowed_classes")-1); + if(classes && (Z_TYPE_P(classes) == IS_ARRAY || !zend_is_true(classes TSRMLS_CC))) { + ALLOC_HASHTABLE(class_hash); + zend_hash_init(class_hash, (Z_TYPE_P(classes) == IS_ARRAY)?zend_hash_num_elements(Z_ARRVAL_P(classes)):0, NULL, NULL, 0); + } + if(class_hash && Z_TYPE_P(classes) == IS_ARRAY) { + zval *entry; + zend_string *lcname; + + ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(classes), entry) { + convert_to_string_ex(entry); + lcname = zend_string_alloc(Z_STRLEN_P(entry), 0); + zend_str_tolower_copy(lcname->val, Z_STRVAL_P(entry), Z_STRLEN_P(entry)); + zend_hash_add_empty_element(class_hash, lcname); + zend_string_release(lcname); + } ZEND_HASH_FOREACH_END(); + } + } + + if (!php_var_unserialize_ex(return_value, &p, p + buf_len, &var_hash, class_hash TSRMLS_CC)) { PHP_VAR_UNSERIALIZE_DESTROY(var_hash); + if(class_hash) { + zend_hash_destroy(class_hash); + FREE_HASHTABLE(class_hash); + } zval_dtor(return_value); if (!EG(exception)) { php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Error at offset " ZEND_LONG_FMT " of %d bytes", (zend_long)((char*)p - buf), buf_len); @@ -1018,6 +1044,10 @@ PHP_FUNCTION(unserialize) RETURN_FALSE; } PHP_VAR_UNSERIALIZE_DESTROY(var_hash); + if(class_hash) { + zend_hash_destroy(class_hash); + FREE_HASHTABLE(class_hash); + } } /* }}} */ diff --git a/ext/standard/var_unserializer.c b/ext/standard/var_unserializer.c index c7641b1334cda..d8b94e75cc6a3 100644 --- a/ext/standard/var_unserializer.c +++ b/ext/standard/var_unserializer.c @@ -1,4 +1,4 @@ -/* Generated by re2c 0.13.5 */ +/* Generated by re2c 0.13.7.5 */ #line 1 "ext/standard/var_unserializer.re" /* +----------------------------------------------------------------------+ @@ -226,6 +226,26 @@ static zend_string *unserialize_str(const unsigned char **p, size_t len, size_t return str; } +static inline int unserialize_allowed_class(zend_string *class_name, HashTable *classes) +{ + zend_string *lcname; + int res; + ALLOCA_FLAG(use_heap) + + if(classes == NULL) { + return 1; + } + if(!zend_hash_num_elements(classes)) { + return 0; + } + + STR_ALLOCA_ALLOC(lcname, class_name->len, use_heap); + zend_str_tolower_copy(lcname->val, class_name->val, class_name->len); + res = zend_hash_exists(classes, lcname); + STR_ALLOCA_FREE(lcname, use_heap); + return res; +} + #define YYFILL(n) do { } while (0) #define YYCTYPE unsigned char #define YYCURSOR cursor @@ -233,7 +253,7 @@ static zend_string *unserialize_str(const unsigned char **p, size_t len, size_t #define YYMARKER marker -#line 241 "ext/standard/var_unserializer.re" +#line 261 "ext/standard/var_unserializer.re" @@ -293,8 +313,8 @@ static inline size_t parse_uiv(const unsigned char *p) return result; } -#define UNSERIALIZE_PARAMETER zval *rval, const unsigned char **p, const unsigned char *max, php_unserialize_data_t *var_hash TSRMLS_DC -#define UNSERIALIZE_PASSTHRU rval, p, max, var_hash TSRMLS_CC +#define UNSERIALIZE_PARAMETER zval *rval, const unsigned char **p, const unsigned char *max, php_unserialize_data_t *var_hash, HashTable *classes TSRMLS_DC +#define UNSERIALIZE_PASSTHRU rval, p, max, var_hash, classes TSRMLS_CC static inline int process_nested_data(UNSERIALIZE_PARAMETER, HashTable *ht, zend_long elements, int objprops) { @@ -302,7 +322,8 @@ static inline int process_nested_data(UNSERIALIZE_PARAMETER, HashTable *ht, zend zval key, *data, d, *old_data; ZVAL_UNDEF(&key); - if (!php_var_unserialize(&key, p, max, NULL TSRMLS_CC)) { + + if (!php_var_unserialize_ex(&key, p, max, NULL, classes TSRMLS_CC)) { zval_dtor(&key); return 0; } @@ -354,7 +375,7 @@ static inline int process_nested_data(UNSERIALIZE_PARAMETER, HashTable *ht, zend zval_dtor(&key); - if (!php_var_unserialize(data, p, max, var_hash TSRMLS_CC)) { + if (!php_var_unserialize_ex(data, p, max, var_hash, classes TSRMLS_CC)) { return 0; } @@ -462,7 +483,14 @@ static inline int object_common2(UNSERIALIZE_PARAMETER, zend_long elements) # pragma optimize("", on) #endif -PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) +PHPAPI int php_var_unserialize(zval *rval, const unsigned char **p, const unsigned char *max, php_unserialize_data_t *var_hash TSRMLS_DC) +{ + HashTable *classes = NULL; + return php_var_unserialize_ex(UNSERIALIZE_PASSTHRU); +} + + +PHPAPI int php_var_unserialize_ex(UNSERIALIZE_PARAMETER) { const unsigned char *cursor, *limit, *marker, *start; zval *rval_ref; @@ -481,7 +509,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) start = cursor; -#line 485 "ext/standard/var_unserializer.c" +#line 513 "ext/standard/var_unserializer.c" { YYCTYPE yych; static const unsigned char yybm[] = { @@ -541,9 +569,9 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) yych = *(YYMARKER = ++YYCURSOR); if (yych == ':') goto yy95; yy3: -#line 826 "ext/standard/var_unserializer.re" +#line 860 "ext/standard/var_unserializer.re" { return 0; } -#line 547 "ext/standard/var_unserializer.c" +#line 575 "ext/standard/var_unserializer.c" yy4: yych = *(YYMARKER = ++YYCURSOR); if (yych == ':') goto yy89; @@ -586,13 +614,13 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) goto yy3; yy14: ++YYCURSOR; -#line 820 "ext/standard/var_unserializer.re" +#line 854 "ext/standard/var_unserializer.re" { /* this is the case where we have less data than planned */ php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Unexpected end of serialized data"); return 0; /* not sure if it should be 0 or 1 here? */ } -#line 596 "ext/standard/var_unserializer.c" +#line 624 "ext/standard/var_unserializer.c" yy16: yych = *++YYCURSOR; goto yy3; @@ -618,11 +646,12 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) if (yybm[0+yych] & 128) { goto yy20; } - if (yych != ':') goto yy18; + if (yych <= '/') goto yy18; + if (yych >= ';') goto yy18; yych = *++YYCURSOR; if (yych != '"') goto yy18; ++YYCURSOR; -#line 681 "ext/standard/var_unserializer.re" +#line 709 "ext/standard/var_unserializer.re" { size_t len, len2, len3, maxlen; zend_long elements; @@ -672,6 +701,12 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) class_name = zend_string_init(str, len, 0); do { + if(!unserialize_allowed_class(class_name, classes)) { + incomplete_class = 1; + ce = PHP_IC_ENTRY; + break; + } + /* Try to find class directly */ BG(serialize_lock)++; ce = zend_lookup_class(class_name TSRMLS_CC); @@ -761,7 +796,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) return object_common2(UNSERIALIZE_PASSTHRU, elements); } -#line 765 "ext/standard/var_unserializer.c" +#line 800 "ext/standard/var_unserializer.c" yy25: yych = *++YYCURSOR; if (yych <= ',') { @@ -786,7 +821,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) yych = *++YYCURSOR; if (yych != '"') goto yy18; ++YYCURSOR; -#line 673 "ext/standard/var_unserializer.re" +#line 701 "ext/standard/var_unserializer.re" { //??? INIT_PZVAL(rval); @@ -794,7 +829,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) return object_common2(UNSERIALIZE_PASSTHRU, object_common1(UNSERIALIZE_PASSTHRU, ZEND_STANDARD_CLASS_DEF_PTR)); } -#line 798 "ext/standard/var_unserializer.c" +#line 833 "ext/standard/var_unserializer.c" yy32: yych = *++YYCURSOR; if (yych == '+') goto yy33; @@ -815,7 +850,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) yych = *++YYCURSOR; if (yych != '{') goto yy18; ++YYCURSOR; -#line 652 "ext/standard/var_unserializer.re" +#line 680 "ext/standard/var_unserializer.re" { zend_long elements = parse_iv(start + 2); /* use iv() not uiv() in order to check data range */ @@ -836,7 +871,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) return finish_nested_data(UNSERIALIZE_PASSTHRU); } -#line 840 "ext/standard/var_unserializer.c" +#line 875 "ext/standard/var_unserializer.c" yy39: yych = *++YYCURSOR; if (yych == '+') goto yy40; @@ -857,7 +892,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) yych = *++YYCURSOR; if (yych != '"') goto yy18; ++YYCURSOR; -#line 624 "ext/standard/var_unserializer.re" +#line 652 "ext/standard/var_unserializer.re" { size_t len, maxlen; zend_string *str; @@ -885,7 +920,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) ZVAL_STR(rval, str); return 1; } -#line 889 "ext/standard/var_unserializer.c" +#line 924 "ext/standard/var_unserializer.c" yy46: yych = *++YYCURSOR; if (yych == '+') goto yy47; @@ -906,7 +941,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) yych = *++YYCURSOR; if (yych != '"') goto yy18; ++YYCURSOR; -#line 597 "ext/standard/var_unserializer.re" +#line 625 "ext/standard/var_unserializer.re" { size_t len, maxlen; char *str; @@ -933,7 +968,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) ZVAL_STRINGL(rval, str, len); return 1; } -#line 937 "ext/standard/var_unserializer.c" +#line 972 "ext/standard/var_unserializer.c" yy53: yych = *++YYCURSOR; if (yych <= '/') { @@ -1021,7 +1056,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) } yy63: ++YYCURSOR; -#line 588 "ext/standard/var_unserializer.re" +#line 616 "ext/standard/var_unserializer.re" { #if SIZEOF_ZEND_LONG == 4 use_double: @@ -1030,7 +1065,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) ZVAL_DOUBLE(rval, zend_strtod((const char *)start + 2, NULL)); return 1; } -#line 1034 "ext/standard/var_unserializer.c" +#line 1069 "ext/standard/var_unserializer.c" yy65: yych = *++YYCURSOR; if (yych <= ',') { @@ -1089,7 +1124,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) yych = *++YYCURSOR; if (yych != ';') goto yy18; ++YYCURSOR; -#line 572 "ext/standard/var_unserializer.re" +#line 600 "ext/standard/var_unserializer.re" { *p = YYCURSOR; @@ -1105,7 +1140,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) return 1; } -#line 1109 "ext/standard/var_unserializer.c" +#line 1144 "ext/standard/var_unserializer.c" yy76: yych = *++YYCURSOR; if (yych == 'N') goto yy73; @@ -1132,7 +1167,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) if (yych <= '9') goto yy79; if (yych != ';') goto yy18; ++YYCURSOR; -#line 546 "ext/standard/var_unserializer.re" +#line 574 "ext/standard/var_unserializer.re" { #if SIZEOF_ZEND_LONG == 4 int digits = YYCURSOR - start - 3; @@ -1158,7 +1193,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) ZVAL_LONG(rval, parse_iv(start + 2)); return 1; } -#line 1162 "ext/standard/var_unserializer.c" +#line 1197 "ext/standard/var_unserializer.c" yy83: yych = *++YYCURSOR; if (yych <= '/') goto yy18; @@ -1166,22 +1201,22 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) yych = *++YYCURSOR; if (yych != ';') goto yy18; ++YYCURSOR; -#line 540 "ext/standard/var_unserializer.re" +#line 568 "ext/standard/var_unserializer.re" { *p = YYCURSOR; ZVAL_BOOL(rval, parse_iv(start + 2)); return 1; } -#line 1176 "ext/standard/var_unserializer.c" +#line 1211 "ext/standard/var_unserializer.c" yy87: ++YYCURSOR; -#line 534 "ext/standard/var_unserializer.re" +#line 562 "ext/standard/var_unserializer.re" { *p = YYCURSOR; ZVAL_NULL(rval); return 1; } -#line 1185 "ext/standard/var_unserializer.c" +#line 1220 "ext/standard/var_unserializer.c" yy89: yych = *++YYCURSOR; if (yych <= ',') { @@ -1204,7 +1239,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) if (yych <= '9') goto yy91; if (yych != ';') goto yy18; ++YYCURSOR; -#line 511 "ext/standard/var_unserializer.re" +#line 539 "ext/standard/var_unserializer.re" { zend_long id; @@ -1227,7 +1262,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) return 1; } -#line 1231 "ext/standard/var_unserializer.c" +#line 1266 "ext/standard/var_unserializer.c" yy95: yych = *++YYCURSOR; if (yych <= ',') { @@ -1250,7 +1285,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) if (yych <= '9') goto yy97; if (yych != ';') goto yy18; ++YYCURSOR; -#line 489 "ext/standard/var_unserializer.re" +#line 517 "ext/standard/var_unserializer.re" { zend_long id; @@ -1272,9 +1307,9 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) return 1; } -#line 1276 "ext/standard/var_unserializer.c" +#line 1311 "ext/standard/var_unserializer.c" } -#line 828 "ext/standard/var_unserializer.re" +#line 862 "ext/standard/var_unserializer.re" return 0; diff --git a/ext/standard/var_unserializer.re b/ext/standard/var_unserializer.re index b8c65b7c4bd72..7e0dc314d6f9a 100644 --- a/ext/standard/var_unserializer.re +++ b/ext/standard/var_unserializer.re @@ -224,6 +224,26 @@ static zend_string *unserialize_str(const unsigned char **p, size_t len, size_t return str; } +static inline int unserialize_allowed_class(zend_string *class_name, HashTable *classes) +{ + zend_string *lcname; + int res; + ALLOCA_FLAG(use_heap) + + if(classes == NULL) { + return 1; + } + if(!zend_hash_num_elements(classes)) { + return 0; + } + + STR_ALLOCA_ALLOC(lcname, class_name->len, use_heap); + zend_str_tolower_copy(lcname->val, class_name->val, class_name->len); + res = zend_hash_exists(classes, lcname); + STR_ALLOCA_FREE(lcname, use_heap); + return res; +} + #define YYFILL(n) do { } while (0) #define YYCTYPE unsigned char #define YYCURSOR cursor @@ -297,8 +317,8 @@ static inline size_t parse_uiv(const unsigned char *p) return result; } -#define UNSERIALIZE_PARAMETER zval *rval, const unsigned char **p, const unsigned char *max, php_unserialize_data_t *var_hash TSRMLS_DC -#define UNSERIALIZE_PASSTHRU rval, p, max, var_hash TSRMLS_CC +#define UNSERIALIZE_PARAMETER zval *rval, const unsigned char **p, const unsigned char *max, php_unserialize_data_t *var_hash, HashTable *classes TSRMLS_DC +#define UNSERIALIZE_PASSTHRU rval, p, max, var_hash, classes TSRMLS_CC static inline int process_nested_data(UNSERIALIZE_PARAMETER, HashTable *ht, zend_long elements, int objprops) { @@ -306,7 +326,8 @@ static inline int process_nested_data(UNSERIALIZE_PARAMETER, HashTable *ht, zend zval key, *data, d, *old_data; ZVAL_UNDEF(&key); - if (!php_var_unserialize(&key, p, max, NULL TSRMLS_CC)) { + + if (!php_var_unserialize_ex(&key, p, max, NULL, classes TSRMLS_CC)) { zval_dtor(&key); return 0; } @@ -358,7 +379,7 @@ static inline int process_nested_data(UNSERIALIZE_PARAMETER, HashTable *ht, zend zval_dtor(&key); - if (!php_var_unserialize(data, p, max, var_hash TSRMLS_CC)) { + if (!php_var_unserialize_ex(data, p, max, var_hash, classes TSRMLS_CC)) { return 0; } @@ -466,7 +487,14 @@ static inline int object_common2(UNSERIALIZE_PARAMETER, zend_long elements) # pragma optimize("", on) #endif -PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) +PHPAPI int php_var_unserialize(zval *rval, const unsigned char **p, const unsigned char *max, php_unserialize_data_t *var_hash TSRMLS_DC) +{ + HashTable *classes = NULL; + return php_var_unserialize_ex(UNSERIALIZE_PASSTHRU); +} + + +PHPAPI int php_var_unserialize_ex(UNSERIALIZE_PARAMETER) { const unsigned char *cursor, *limit, *marker, *start; zval *rval_ref; @@ -727,6 +755,12 @@ object ":" uiv ":" ["] { class_name = zend_string_init(str, len, 0); do { + if(!unserialize_allowed_class(class_name, classes)) { + incomplete_class = 1; + ce = PHP_IC_ENTRY; + break; + } + /* Try to find class directly */ BG(serialize_lock)++; ce = zend_lookup_class(class_name TSRMLS_CC);