From b221df5549533fe04c151cca85be43eb624a643d Mon Sep 17 00:00:00 2001 From: Stanislav Malyshev Date: Tue, 4 Aug 2015 23:56:15 -0700 Subject: 5.4.45 next --- NEWS | 4 +++- configure.in | 2 +- main/php_version.h | 6 +++--- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/NEWS b/NEWS index 1dcbbd2c56..a3b5d82910 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,8 @@ PHP NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| -?? ??? 2015 PHP 5.4.44 +?? ??? 2015 PHP 5.4.45 + +06 Aug 2015 PHP 5.4.44 - Core: . Fixed bug #69793 (Remotely triggerable stack exhaustion via recursive diff --git a/configure.in b/configure.in index 2c2edc9426..2c12f5471d 100644 --- a/configure.in +++ b/configure.in @@ -119,7 +119,7 @@ int zend_sprintf(char *buffer, const char *format, ...); PHP_MAJOR_VERSION=5 PHP_MINOR_VERSION=4 -PHP_RELEASE_VERSION=44 +PHP_RELEASE_VERSION=45 PHP_EXTRA_VERSION="-dev" PHP_VERSION="$PHP_MAJOR_VERSION.$PHP_MINOR_VERSION.$PHP_RELEASE_VERSION$PHP_EXTRA_VERSION" PHP_VERSION_ID=`expr [$]PHP_MAJOR_VERSION \* 10000 + [$]PHP_MINOR_VERSION \* 100 + [$]PHP_RELEASE_VERSION` diff --git a/main/php_version.h b/main/php_version.h index 2ff0add16b..49c00afc70 100644 --- a/main/php_version.h +++ b/main/php_version.h @@ -2,7 +2,7 @@ /* edit configure.in to change version number */ #define PHP_MAJOR_VERSION 5 #define PHP_MINOR_VERSION 4 -#define PHP_RELEASE_VERSION 44 +#define PHP_RELEASE_VERSION 45 #define PHP_EXTRA_VERSION "-dev" -#define PHP_VERSION "5.4.44-dev" -#define PHP_VERSION_ID 50444 +#define PHP_VERSION "5.4.45-dev" +#define PHP_VERSION_ID 50445 -- cgit v1.2.1 From 1744be2d17befc69bf00033993f4081852a747d6 Mon Sep 17 00:00:00 2001 From: Stanislav Malyshev Date: Sun, 16 Aug 2015 17:16:15 -0700 Subject: Fix for bug #69782 --- ext/xsl/xsltprocessor.c | 142 +++++++++++++++++++++++++----------------------- 1 file changed, 73 insertions(+), 69 deletions(-) diff --git a/ext/xsl/xsltprocessor.c b/ext/xsl/xsltprocessor.c index 67c90f501f..d21a8ebcb7 100644 --- a/ext/xsl/xsltprocessor.c +++ b/ext/xsl/xsltprocessor.c @@ -81,10 +81,10 @@ ZEND_END_ARG_INFO(); /* }}} */ /* -* class xsl_xsltprocessor +* class xsl_xsltprocessor * * URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html# -* Since: +* Since: */ const zend_function_entry php_xsl_xsltprocessor_class_functions[] = { @@ -111,9 +111,9 @@ static char *php_xsl_xslt_string_to_xpathexpr(const char *str TSRMLS_DC) xmlChar *value; int str_len; - + str_len = xmlStrlen(string) + 3; - + if (xmlStrchr(string, '"')) { if (xmlStrchr(string, '\'')) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot create XPath expression (string contains both quote and double-quotes)"); @@ -133,7 +133,7 @@ static char *php_xsl_xslt_string_to_xpathexpr(const char *str TSRMLS_DC) Translates a PHP array to a libxslt parameters array */ static char **php_xsl_xslt_make_params(HashTable *parht, int xpath_params TSRMLS_DC) { - + int parsize; zval **value; char *xpath_expr, *string_key = NULL; @@ -158,7 +158,7 @@ static char **php_xsl_xslt_make_params(HashTable *parht, int xpath_params TSRMLS SEPARATE_ZVAL(value); convert_to_string(*value); } - + if (!xpath_params) { xpath_expr = php_xsl_xslt_string_to_xpathexpr(Z_STRVAL_PP(value) TSRMLS_CC); } else { @@ -192,7 +192,7 @@ static void xsl_ext_function_php(xmlXPathParserContextPtr ctxt, int nargs, int t char *str; char *callable = NULL; xsl_object *intern; - + TSRMLS_FETCH(); if (! zend_is_executing(TSRMLS_C)) { @@ -219,15 +219,17 @@ static void xsl_ext_function_php(xmlXPathParserContextPtr ctxt, int nargs, int t } } } - + if (error == 1) { for (i = nargs - 1; i >= 0; i--) { obj = valuePop(ctxt); - xmlXPathFreeObject(obj); + if (obj) { + xmlXPathFreeObject(obj); + } } return; } - + fci.param_count = nargs - 1; if (fci.param_count > 0) { fci.params = safe_emalloc(fci.param_count, sizeof(zval**), 0); @@ -265,7 +267,7 @@ static void xsl_ext_function_php(xmlXPathParserContextPtr ctxt, int nargs, int t if (node->type == XML_NAMESPACE_DECL) { xmlNsPtr curns; xmlNodePtr nsparent; - + nsparent = node->_private; curns = xmlNewNs(NULL, node->name, NULL); if (node->children) { @@ -297,14 +299,16 @@ static void xsl_ext_function_php(xmlXPathParserContextPtr ctxt, int nargs, int t xmlXPathFreeObject(obj); fci.params[i] = &args[i]; } - + fci.size = sizeof(fci); fci.function_table = EG(function_table); - + obj = valuePop(ctxt); - if (obj->stringval == NULL) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Handler name must be a string"); - xmlXPathFreeObject(obj); + if (obj == NULL || obj->stringval == NULL) { + if (obj) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Handler name must be a string"); + xmlXPathFreeObject(obj); + } valuePush(ctxt, xmlXPathNewString("")); if (fci.param_count > 0) { for (i = 0; i < nargs - 1; i++) { @@ -313,12 +317,12 @@ static void xsl_ext_function_php(xmlXPathParserContextPtr ctxt, int nargs, int t efree(args); efree(fci.params); } - return; + return; } INIT_PZVAL(&handler); ZVAL_STRING(&handler, obj->stringval, 1); xmlXPathFreeObject(obj); - + fci.function_name = &handler; fci.symbol_table = NULL; fci.object_ptr = NULL; @@ -328,7 +332,7 @@ static void xsl_ext_function_php(xmlXPathParserContextPtr ctxt, int nargs, int t if (!zend_make_callable(&handler, &callable TSRMLS_CC)) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to call handler %s()", callable); valuePush(ctxt, xmlXPathNewString("")); - } else if ( intern->registerPhpFunctions == 2 && zend_hash_exists(intern->registered_phpfunctions, callable, strlen(callable) + 1) == 0) { + } else if ( intern->registerPhpFunctions == 2 && zend_hash_exists(intern->registered_phpfunctions, callable, strlen(callable) + 1) == 0) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Not allowed to call handler '%s()'", callable); /* Push an empty string, so that we at least have an xslt result... */ valuePush(ctxt, xmlXPathNewString("")); @@ -392,7 +396,7 @@ void xsl_ext_function_object_php(xmlXPathParserContextPtr ctxt, int nargs) /* {{ /* {{{ proto void xsl_xsltprocessor_import_stylesheet(domdocument doc); URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html# -Since: +Since: */ PHP_FUNCTION(xsl_xsltprocessor_import_stylesheet) { @@ -404,13 +408,13 @@ PHP_FUNCTION(xsl_xsltprocessor_import_stylesheet) xmlNode *nodep = NULL; zend_object_handlers *std_hnd; zval *cloneDocu, *member; - + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Oo", &id, xsl_xsltprocessor_class_entry, &docp) == FAILURE) { RETURN_FALSE; } nodep = php_libxml_import_node(docp TSRMLS_CC); - + if (nodep) { doc = nodep->doc; } @@ -419,7 +423,7 @@ PHP_FUNCTION(xsl_xsltprocessor_import_stylesheet) RETURN_FALSE; } - /* libxslt uses _private, so we must copy the imported + /* libxslt uses _private, so we must copy the imported stylesheet document otherwise the node proxies will be a mess */ newdoc = xmlCopyDoc(doc, 1); xmlNodeSetBase((xmlNodePtr) newdoc, (xmlChar *)doc->URL); @@ -436,7 +440,7 @@ PHP_FUNCTION(xsl_xsltprocessor_import_stylesheet) RETURN_FALSE; } - intern = (xsl_object *)zend_object_store_get_object(id TSRMLS_CC); + intern = (xsl_object *)zend_object_store_get_object(id TSRMLS_CC); std_hnd = zend_get_std_object_handlers(); MAKE_STD_ZVAL(member); @@ -463,10 +467,10 @@ PHP_FUNCTION(xsl_xsltprocessor_import_stylesheet) intern->hasKeys = clone_docu; } - if ((oldsheetp = (xsltStylesheetPtr)intern->ptr)) { + if ((oldsheetp = (xsltStylesheetPtr)intern->ptr)) { /* free wrapper */ if (((xsltStylesheetPtr) intern->ptr)->_private != NULL) { - ((xsltStylesheetPtr) intern->ptr)->_private = NULL; + ((xsltStylesheetPtr) intern->ptr)->_private = NULL; } xsltFreeStylesheet((xsltStylesheetPtr) intern->ptr); intern->ptr = NULL; @@ -494,7 +498,7 @@ static xmlDocPtr php_xsl_apply_stylesheet(zval *id, xsl_object *intern, xsltStyl xsltSecurityPrefsPtr secPrefs = NULL; node = php_libxml_import_node(docp TSRMLS_CC); - + if (node) { doc = node->doc; } @@ -507,7 +511,7 @@ static xmlDocPtr php_xsl_apply_stylesheet(zval *id, xsl_object *intern, xsltStyl php_error_docref(NULL TSRMLS_CC, E_WARNING, "No stylesheet associated to this object"); return NULL; } - + if (intern->profiling) { if (php_check_open_basedir(intern->profiling TSRMLS_CC)) { f = NULL; @@ -517,7 +521,7 @@ static xmlDocPtr php_xsl_apply_stylesheet(zval *id, xsl_object *intern, xsltStyl } else { f = NULL; } - + if (intern->parameter) { params = php_xsl_xslt_make_params(intern->parameter, 0 TSRMLS_CC); } @@ -549,7 +553,7 @@ static xmlDocPtr php_xsl_apply_stylesheet(zval *id, xsl_object *intern, xsltStyl efree(member); secPrefsValue = intern->securityPrefs; - + /* This whole if block can be removed, when we remove the xsl.security_prefs php.ini option in PHP 6+ */ secPrefsIni= INI_INT("xsl.security_prefs"); /* if secPrefsIni has the same value as secPrefsValue, all is fine */ @@ -569,38 +573,38 @@ static xmlDocPtr php_xsl_apply_stylesheet(zval *id, xsl_object *intern, xsltStyl /* if securityPrefs is set to NONE, we don't have to do any checks, but otherwise... */ if (secPrefsValue != XSL_SECPREF_NONE) { - secPrefs = xsltNewSecurityPrefs(); - if (secPrefsValue & XSL_SECPREF_READ_FILE ) { - if (0 != xsltSetSecurityPrefs(secPrefs, XSLT_SECPREF_READ_FILE, xsltSecurityForbid)) { + secPrefs = xsltNewSecurityPrefs(); + if (secPrefsValue & XSL_SECPREF_READ_FILE ) { + if (0 != xsltSetSecurityPrefs(secPrefs, XSLT_SECPREF_READ_FILE, xsltSecurityForbid)) { secPrefsError = 1; } } - if (secPrefsValue & XSL_SECPREF_WRITE_FILE ) { - if (0 != xsltSetSecurityPrefs(secPrefs, XSLT_SECPREF_WRITE_FILE, xsltSecurityForbid)) { + if (secPrefsValue & XSL_SECPREF_WRITE_FILE ) { + if (0 != xsltSetSecurityPrefs(secPrefs, XSLT_SECPREF_WRITE_FILE, xsltSecurityForbid)) { secPrefsError = 1; } } - if (secPrefsValue & XSL_SECPREF_CREATE_DIRECTORY ) { - if (0 != xsltSetSecurityPrefs(secPrefs, XSLT_SECPREF_CREATE_DIRECTORY, xsltSecurityForbid)) { + if (secPrefsValue & XSL_SECPREF_CREATE_DIRECTORY ) { + if (0 != xsltSetSecurityPrefs(secPrefs, XSLT_SECPREF_CREATE_DIRECTORY, xsltSecurityForbid)) { secPrefsError = 1; } } - if (secPrefsValue & XSL_SECPREF_READ_NETWORK) { - if (0 != xsltSetSecurityPrefs(secPrefs, XSLT_SECPREF_READ_NETWORK, xsltSecurityForbid)) { + if (secPrefsValue & XSL_SECPREF_READ_NETWORK) { + if (0 != xsltSetSecurityPrefs(secPrefs, XSLT_SECPREF_READ_NETWORK, xsltSecurityForbid)) { secPrefsError = 1; } } - if (secPrefsValue & XSL_SECPREF_WRITE_NETWORK) { - if (0 != xsltSetSecurityPrefs(secPrefs, XSLT_SECPREF_WRITE_NETWORK, xsltSecurityForbid)) { + if (secPrefsValue & XSL_SECPREF_WRITE_NETWORK) { + if (0 != xsltSetSecurityPrefs(secPrefs, XSLT_SECPREF_WRITE_NETWORK, xsltSecurityForbid)) { secPrefsError = 1; } } - - if (0 != xsltSetCtxtSecurityPrefs(secPrefs, ctxt)) { + + if (0 != xsltSetCtxtSecurityPrefs(secPrefs, ctxt)) { secPrefsError = 1; } } - + if (secPrefsError == 1) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Can't set libxslt security properties, not doing transformation for security reasons"); } else { @@ -609,7 +613,7 @@ static xmlDocPtr php_xsl_apply_stylesheet(zval *id, xsl_object *intern, xsltStyl if (f) { fclose(f); } - + xsltFreeTransformContext(ctxt); if (secPrefs) { xsltFreeSecurityPrefs(secPrefs); @@ -617,7 +621,7 @@ static xmlDocPtr php_xsl_apply_stylesheet(zval *id, xsl_object *intern, xsltStyl if (intern->node_list != NULL) { zend_hash_destroy(intern->node_list); - FREE_HASHTABLE(intern->node_list); + FREE_HASHTABLE(intern->node_list); intern->node_list = NULL; } @@ -640,7 +644,7 @@ static xmlDocPtr php_xsl_apply_stylesheet(zval *id, xsl_object *intern, xsltStyl /* {{{ proto domdocument xsl_xsltprocessor_transform_to_doc(domnode doc); URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html# -Since: +Since: */ PHP_FUNCTION(xsl_xsltprocessor_transform_to_doc) { @@ -677,13 +681,13 @@ PHP_FUNCTION(xsl_xsltprocessor_transform_to_doc) found = zend_lookup_class(ret_class, ret_class_len, &ce TSRMLS_CC); if ((found != SUCCESS) || !instanceof_function(*ce, curce TSRMLS_CC)) { xmlFreeDoc(newdocp); - php_error_docref(NULL TSRMLS_CC, E_WARNING, + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Expecting class compatible with %s, '%s' given", curclass_name, ret_class); RETURN_FALSE; } object_init_ex(return_value, *ce); - + interndoc = (php_libxml_node_object *)zend_objects_get_address(return_value TSRMLS_CC); php_libxml_increment_doc_ref(interndoc, newdocp TSRMLS_CC); php_libxml_increment_node_ptr(interndoc, (xmlNodePtr)newdocp, (void *)interndoc TSRMLS_CC); @@ -693,7 +697,7 @@ PHP_FUNCTION(xsl_xsltprocessor_transform_to_doc) } else { RETURN_FALSE; } - + } /* }}} end xsl_xsltprocessor_transform_to_doc */ @@ -707,7 +711,7 @@ PHP_FUNCTION(xsl_xsltprocessor_transform_to_uri) int ret, uri_len; char *uri; xsl_object *intern; - + id = getThis(); intern = (xsl_object *)zend_object_store_get_object(id TSRMLS_CC); sheetp = (xsltStylesheetPtr) intern->ptr; @@ -739,7 +743,7 @@ PHP_FUNCTION(xsl_xsltprocessor_transform_to_xml) xmlChar *doc_txt_ptr; int doc_txt_len; xsl_object *intern; - + id = getThis(); intern = (xsl_object *)zend_object_store_get_object(id TSRMLS_CC); sheetp = (xsltStylesheetPtr) intern->ptr; @@ -770,7 +774,7 @@ PHP_FUNCTION(xsl_xsltprocessor_transform_to_xml) */ PHP_FUNCTION(xsl_xsltprocessor_set_parameter) { - + zval *id; zval *array_value, **entry, *new_string; xsl_object *intern; @@ -786,34 +790,34 @@ PHP_FUNCTION(xsl_xsltprocessor_set_parameter) while (zend_hash_get_current_data(Z_ARRVAL_P(array_value), (void **)&entry) == SUCCESS) { SEPARATE_ZVAL(entry); convert_to_string_ex(entry); - + if (zend_hash_get_current_key_ex(Z_ARRVAL_P(array_value), &string_key, &string_key_len, &idx, 0, NULL) != HASH_KEY_IS_STRING) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid parameter array"); RETURN_FALSE; } - + ALLOC_ZVAL(new_string); Z_ADDREF_PP(entry); COPY_PZVAL_TO_ZVAL(*new_string, *entry); - + zend_hash_update(intern->parameter, string_key, string_key_len, &new_string, sizeof(zval*), NULL); zend_hash_move_forward(Z_ARRVAL_P(array_value)); } RETURN_TRUE; } else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "sss", &namespace, &namespace_len, &name, &name_len, &value, &value_len) == SUCCESS) { - + intern = (xsl_object *)zend_object_store_get_object(id TSRMLS_CC); - + MAKE_STD_ZVAL(new_string); ZVAL_STRING(new_string, value, 1); - + zend_hash_update(intern->parameter, name, name_len + 1, &new_string, sizeof(zval*), NULL); RETURN_TRUE; } else { WRONG_PARAM_COUNT; } - + } /* }}} end xsl_xsltprocessor_set_parameter */ @@ -828,7 +832,7 @@ PHP_FUNCTION(xsl_xsltprocessor_get_parameter) xsl_object *intern; DOM_GET_THIS(id); - + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &namespace, &namespace_len, &name, &name_len) == FAILURE) { RETURN_FALSE; } @@ -852,7 +856,7 @@ PHP_FUNCTION(xsl_xsltprocessor_remove_parameter) xsl_object *intern; DOM_GET_THIS(id); - + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &namespace, &namespace_len, &name, &name_len) == FAILURE) { RETURN_FALSE; } @@ -876,7 +880,7 @@ PHP_FUNCTION(xsl_xsltprocessor_register_php_functions) char *name; DOM_GET_THIS(id); - + if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "a", &array_value) == SUCCESS) { intern = (xsl_object *)zend_object_store_get_object(id TSRMLS_CC); zend_hash_internal_pointer_reset(Z_ARRVAL_P(array_value)); @@ -884,10 +888,10 @@ PHP_FUNCTION(xsl_xsltprocessor_register_php_functions) while (zend_hash_get_current_data(Z_ARRVAL_P(array_value), (void **)&entry) == SUCCESS) { SEPARATE_ZVAL(entry); convert_to_string_ex(entry); - + MAKE_STD_ZVAL(new_string); ZVAL_LONG(new_string,1); - + zend_hash_update(intern->registered_phpfunctions, Z_STRVAL_PP(entry), Z_STRLEN_PP(entry) + 1, &new_string, sizeof(zval*), NULL); zend_hash_move_forward(Z_ARRVAL_P(array_value)); } @@ -895,17 +899,17 @@ PHP_FUNCTION(xsl_xsltprocessor_register_php_functions) } else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "s", &name, &name_len) == SUCCESS) { intern = (xsl_object *)zend_object_store_get_object(id TSRMLS_CC); - + MAKE_STD_ZVAL(new_string); ZVAL_LONG(new_string,1); zend_hash_update(intern->registered_phpfunctions, name, name_len + 1, &new_string, sizeof(zval*), NULL); intern->registerPhpFunctions = 2; - + } else { intern = (xsl_object *)zend_object_store_get_object(id TSRMLS_CC); intern->registerPhpFunctions = 1; } - + } /* }}} end xsl_xsltprocessor_register_php_functions(); */ @@ -947,7 +951,7 @@ PHP_FUNCTION(xsl_xsltprocessor_set_security_prefs) return; } intern = (xsl_object *)zend_object_store_get_object(id TSRMLS_CC); - oldSecurityPrefs = intern->securityPrefs; + oldSecurityPrefs = intern->securityPrefs; intern->securityPrefs = securityPrefs; /* set this to 1 so that we know, it was set through this method. Can be removed, when we remove the ini setting */ intern->securityPrefsSet = 1; -- cgit v1.2.1 From df4bf28f9f104ca3ef78ed94b497859f15b004e5 Mon Sep 17 00:00:00 2001 From: Stanislav Malyshev Date: Sun, 23 Aug 2015 13:27:59 -0700 Subject: Fix bug #70219 (Use after free vulnerability in session deserializer) --- ext/session/session.c | 36 +- ext/session/tests/session_decode_error2.phpt | 518 +++++------------------ ext/session/tests/session_decode_variation3.phpt | 2 +- ext/standard/tests/serialize/bug70219.phpt | 38 ++ ext/standard/var_unserializer.c | 68 +-- ext/standard/var_unserializer.re | 64 +-- 6 files changed, 228 insertions(+), 498 deletions(-) create mode 100644 ext/standard/tests/serialize/bug70219.phpt diff --git a/ext/session/session.c b/ext/session/session.c index 306aba3a7d..0e53c62133 100644 --- a/ext/session/session.c +++ b/ext/session/session.c @@ -210,16 +210,18 @@ static char *php_session_encode(int *newlen TSRMLS_DC) /* {{{ */ } /* }}} */ -static void php_session_decode(const char *val, int vallen TSRMLS_DC) /* {{{ */ +static int php_session_decode(const char *val, int vallen TSRMLS_DC) /* {{{ */ { if (!PS(serializer)) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown session.serialize_handler. Failed to decode session object"); - return; + return FAILURE; } if (PS(serializer)->decode(val, vallen TSRMLS_CC) == FAILURE) { php_session_destroy(TSRMLS_C); php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to decode session object. Session has been destroyed"); + return FAILURE; } + return SUCCESS; } /* }}} */ @@ -413,7 +415,7 @@ PHPAPI char *php_session_create_id(PS_CREATE_SID_ARGS) /* {{{ */ php_error_docref(NULL TSRMLS_CC, E_WARNING, "The ini setting hash_bits_per_character is out of range (should be 4, 5, or 6) - using 4 for now"); } - + outid = emalloc((size_t)((digest_len + 2) * ((8.0f / PS(hash_bits_per_character)) + 0.5))); j = (int) (bin_to_readable((char *)digest, digest_len, outid, (char)PS(hash_bits_per_character)) - outid); efree(digest); @@ -855,8 +857,11 @@ PS_SERIALIZER_DECODE_FUNC(php_binary) /* {{{ */ ALLOC_INIT_ZVAL(current); if (php_var_unserialize(¤t, (const unsigned char **) &p, (const unsigned char *) endptr, &var_hash TSRMLS_CC)) { php_set_session_var(name, namelen, current, &var_hash TSRMLS_CC); + } else { + PHP_VAR_UNSERIALIZE_DESTROY(var_hash); + return FAILURE; } - zval_ptr_dtor(¤t); + var_push_dtor_no_addref(&var_hash, ¤t); } PS_ADD_VARL(name, namelen); efree(name); @@ -947,8 +952,13 @@ PS_SERIALIZER_DECODE_FUNC(php) /* {{{ */ ALLOC_INIT_ZVAL(current); if (php_var_unserialize(¤t, (const unsigned char **) &q, (const unsigned char *) endptr, &var_hash TSRMLS_CC)) { php_set_session_var(name, namelen, current, &var_hash TSRMLS_CC); + } else { + var_push_dtor_no_addref(&var_hash, ¤t); + efree(name); + PHP_VAR_UNSERIALIZE_DESTROY(var_hash); + return FAILURE; } - zval_ptr_dtor(¤t); + var_push_dtor_no_addref(&var_hash, ¤t); } PS_ADD_VARL(name, namelen); skip: @@ -1744,7 +1754,7 @@ static PHP_FUNCTION(session_set_save_handler) } efree(name); } - + if (PS(mod) && PS(mod) != &ps_mod_user) { zend_alter_ini_entry("session.save_handler", sizeof("session.save_handler"), "user", sizeof("user")-1, PHP_INI_USER, PHP_INI_STAGE_RUNTIME); } @@ -1922,9 +1932,7 @@ static PHP_FUNCTION(session_decode) return; } - php_session_decode(str, str_len TSRMLS_CC); - - RETURN_TRUE; + RETVAL_BOOL(php_session_decode(str, str_len TSRMLS_CC) == SUCCESS); } /* }}} */ @@ -2516,12 +2524,12 @@ static int php_session_rfc1867_callback(unsigned int event, void *event_data, vo case MULTIPART_EVENT_FILE_START: { multipart_event_file_start *data = (multipart_event_file_start *) event_data; - /* Do nothing when $_POST["PHP_SESSION_UPLOAD_PROGRESS"] is not set + /* Do nothing when $_POST["PHP_SESSION_UPLOAD_PROGRESS"] is not set * or when we have no session id */ if (!Z_TYPE(progress->sid) || !progress->key.c) { break; } - + /* First FILE_START event, initializing data */ if (!progress->data) { @@ -2571,7 +2579,7 @@ static int php_session_rfc1867_callback(unsigned int event, void *event_data, vo add_assoc_zval_ex(progress->current_file, "bytes_processed", sizeof("bytes_processed"), progress->current_file_bytes_processed); add_next_index_zval(progress->files, progress->current_file); - + Z_LVAL_P(progress->post_bytes_processed) = data->post_bytes_processed; php_session_rfc1867_update(progress, 0 TSRMLS_CC); @@ -2583,7 +2591,7 @@ static int php_session_rfc1867_callback(unsigned int event, void *event_data, vo if (!Z_TYPE(progress->sid) || !progress->key.c) { break; } - + Z_LVAL_P(progress->current_file_bytes_processed) = data->offset + data->length; Z_LVAL_P(progress->post_bytes_processed) = data->post_bytes_processed; @@ -2596,7 +2604,7 @@ static int php_session_rfc1867_callback(unsigned int event, void *event_data, vo if (!Z_TYPE(progress->sid) || !progress->key.c) { break; } - + if (data->temp_filename) { add_assoc_string_ex(progress->current_file, "tmp_name", sizeof("tmp_name"), data->temp_filename, 1); } diff --git a/ext/session/tests/session_decode_error2.phpt b/ext/session/tests/session_decode_error2.phpt index 4160f87855..515047b675 100644 --- a/ext/session/tests/session_decode_error2.phpt +++ b/ext/session/tests/session_decode_error2.phpt @@ -53,563 +53,247 @@ array(0) { } -- Iteration 4 -- -bool(true) -array(1) { - ["foo"]=> - NULL + +Warning: session_decode(): Failed to decode session object. Session has been destroyed in %s/session_decode_error2.php on line %d +bool(false) +array(0) { } -- Iteration 5 -- -bool(true) -array(1) { - ["foo"]=> - NULL +bool(false) +array(0) { } -- Iteration 6 -- -bool(true) -array(1) { - ["foo"]=> - NULL +bool(false) +array(0) { } -- Iteration 7 -- -bool(true) -array(1) { - ["foo"]=> - NULL +bool(false) +array(0) { } -- Iteration 8 -- -bool(true) -array(1) { - ["foo"]=> - NULL +bool(false) +array(0) { } -- Iteration 9 -- -bool(true) -array(1) { - ["foo"]=> - NULL +bool(false) +array(0) { } -- Iteration 10 -- -bool(true) -array(1) { - ["foo"]=> - NULL +bool(false) +array(0) { } -- Iteration 11 -- -bool(true) -array(1) { - ["foo"]=> - NULL +bool(false) +array(0) { } -- Iteration 12 -- -bool(true) -array(1) { - ["foo"]=> - NULL +bool(false) +array(0) { } -- Iteration 13 -- -bool(true) -array(1) { - ["foo"]=> - NULL +bool(false) +array(0) { } -- Iteration 14 -- -bool(true) -array(1) { - ["foo"]=> - NULL +bool(false) +array(0) { } -- Iteration 15 -- -bool(true) -array(1) { - ["foo"]=> - NULL +bool(false) +array(0) { } -- Iteration 16 -- -bool(true) -array(1) { - ["foo"]=> - NULL +bool(false) +array(0) { } -- Iteration 17 -- -bool(true) -array(1) { - ["foo"]=> - NULL +bool(false) +array(0) { } -- Iteration 18 -- -bool(true) -array(1) { - ["foo"]=> - NULL +bool(false) +array(0) { } -- Iteration 19 -- -bool(true) -array(1) { - ["foo"]=> - NULL +bool(false) +array(0) { } -- Iteration 20 -- -bool(true) -array(1) { - ["foo"]=> - NULL +bool(false) +array(0) { } -- Iteration 21 -- -bool(true) -array(1) { - ["foo"]=> - NULL +bool(false) +array(0) { } -- Iteration 22 -- -bool(true) -array(1) { - ["foo"]=> - NULL +bool(false) +array(0) { } -- Iteration 23 -- -bool(true) -array(1) { - ["foo"]=> - NULL +bool(false) +array(0) { } -- Iteration 24 -- -bool(true) -array(1) { - ["foo"]=> - NULL +bool(false) +array(0) { } -- Iteration 25 -- -bool(true) -array(1) { - ["foo"]=> - NULL +bool(false) +array(0) { } -- Iteration 26 -- -bool(true) -array(1) { - ["foo"]=> - NULL +bool(false) +array(0) { } -- Iteration 27 -- -bool(true) -array(1) { - ["foo"]=> - NULL +bool(false) +array(0) { } -- Iteration 28 -- -bool(true) -array(1) { - ["foo"]=> - NULL +bool(false) +array(0) { } -- Iteration 29 -- -bool(true) -array(1) { - ["foo"]=> - NULL +bool(false) +array(0) { } -- Iteration 30 -- -bool(true) -array(1) { - ["foo"]=> - NULL +bool(false) +array(0) { } -- Iteration 31 -- -bool(true) -array(1) { - ["foo"]=> - NULL +bool(false) +array(0) { } -- Iteration 32 -- -bool(true) -array(1) { - ["foo"]=> - NULL +bool(false) +array(0) { } -- Iteration 33 -- -bool(true) -array(1) { - ["foo"]=> - NULL +bool(false) +array(0) { } -- Iteration 34 -- -bool(true) -array(1) { - ["foo"]=> - array(3) { - [0]=> - int(1) - [1]=> - int(2) - [2]=> - int(3) - } +bool(false) +array(0) { } -- Iteration 35 -- -bool(true) -array(1) { - ["foo"]=> - array(3) { - [0]=> - int(1) - [1]=> - int(2) - [2]=> - int(3) - } +bool(false) +array(0) { } -- Iteration 36 -- -bool(true) -array(1) { - ["foo"]=> - array(3) { - [0]=> - int(1) - [1]=> - int(2) - [2]=> - int(3) - } +bool(false) +array(0) { } -- Iteration 37 -- -bool(true) -array(1) { - ["foo"]=> - array(3) { - [0]=> - int(1) - [1]=> - int(2) - [2]=> - int(3) - } +bool(false) +array(0) { } -- Iteration 38 -- -bool(true) -array(1) { - ["foo"]=> - array(3) { - [0]=> - int(1) - [1]=> - int(2) - [2]=> - int(3) - } +bool(false) +array(0) { } -- Iteration 39 -- -bool(true) -array(2) { - ["foo"]=> - array(3) { - [0]=> - int(1) - [1]=> - int(2) - [2]=> - int(3) - } - ["guff"]=> - NULL +bool(false) +array(0) { } -- Iteration 40 -- -bool(true) -array(2) { - ["foo"]=> - array(3) { - [0]=> - int(1) - [1]=> - int(2) - [2]=> - int(3) - } - ["guff"]=> - NULL +bool(false) +array(0) { } -- Iteration 41 -- -bool(true) -array(2) { - ["foo"]=> - array(3) { - [0]=> - int(1) - [1]=> - int(2) - [2]=> - int(3) - } - ["guff"]=> - NULL +bool(false) +array(0) { } -- Iteration 42 -- -bool(true) -array(2) { - ["foo"]=> - array(3) { - [0]=> - int(1) - [1]=> - int(2) - [2]=> - int(3) - } - ["guff"]=> - NULL +bool(false) +array(0) { } -- Iteration 43 -- -bool(true) -array(2) { - ["foo"]=> - &array(3) { - [0]=> - int(1) - [1]=> - int(2) - [2]=> - int(3) - } - ["guff"]=> - &array(3) { - [0]=> - int(1) - [1]=> - int(2) - [2]=> - int(3) - } +bool(false) +array(0) { } -- Iteration 44 -- -bool(true) -array(2) { - ["foo"]=> - &array(3) { - [0]=> - int(1) - [1]=> - int(2) - [2]=> - int(3) - } - ["guff"]=> - &array(3) { - [0]=> - int(1) - [1]=> - int(2) - [2]=> - int(3) - } +bool(false) +array(0) { } -- Iteration 45 -- -bool(true) -array(2) { - ["foo"]=> - &array(3) { - [0]=> - int(1) - [1]=> - int(2) - [2]=> - int(3) - } - ["guff"]=> - &array(3) { - [0]=> - int(1) - [1]=> - int(2) - [2]=> - int(3) - } +bool(false) +array(0) { } -- Iteration 46 -- -bool(true) -array(2) { - ["foo"]=> - &array(3) { - [0]=> - int(1) - [1]=> - int(2) - [2]=> - int(3) - } - ["guff"]=> - &array(3) { - [0]=> - int(1) - [1]=> - int(2) - [2]=> - int(3) - } +bool(false) +array(0) { } -- Iteration 47 -- -bool(true) -array(2) { - ["foo"]=> - &array(3) { - [0]=> - int(1) - [1]=> - int(2) - [2]=> - int(3) - } - ["guff"]=> - &array(3) { - [0]=> - int(1) - [1]=> - int(2) - [2]=> - int(3) - } +bool(false) +array(0) { } -- Iteration 48 -- -bool(true) -array(3) { - ["foo"]=> - &array(3) { - [0]=> - int(1) - [1]=> - int(2) - [2]=> - int(3) - } - ["guff"]=> - &array(3) { - [0]=> - int(1) - [1]=> - int(2) - [2]=> - int(3) - } - ["blah"]=> - NULL +bool(false) +array(0) { } -- Iteration 49 -- -bool(true) -array(3) { - ["foo"]=> - &array(3) { - [0]=> - int(1) - [1]=> - int(2) - [2]=> - int(3) - } - ["guff"]=> - &array(3) { - [0]=> - int(1) - [1]=> - int(2) - [2]=> - int(3) - } - ["blah"]=> - NULL +bool(false) +array(0) { } -- Iteration 50 -- -bool(true) -array(3) { - ["foo"]=> - &array(3) { - [0]=> - int(1) - [1]=> - int(2) - [2]=> - int(3) - } - ["guff"]=> - &array(3) { - [0]=> - int(1) - [1]=> - int(2) - [2]=> - int(3) - } - ["blah"]=> - NULL +bool(false) +array(0) { } -- Iteration 51 -- -bool(true) -array(3) { - ["foo"]=> - &array(3) { - [0]=> - int(1) - [1]=> - int(2) - [2]=> - int(3) - } - ["guff"]=> - &array(3) { - [0]=> - int(1) - [1]=> - int(2) - [2]=> - int(3) - } - ["blah"]=> - NULL +bool(false) +array(0) { } -bool(true) -Done +Warning: session_destroy(): Trying to destroy uninitialized session in %s/session_decode_error2.php on line %d +bool(false) +Done diff --git a/ext/session/tests/session_decode_variation3.phpt b/ext/session/tests/session_decode_variation3.phpt index 4a6f768713..096053171d 100644 --- a/ext/session/tests/session_decode_variation3.phpt +++ b/ext/session/tests/session_decode_variation3.phpt @@ -49,7 +49,7 @@ array(3) { } Warning: session_decode(): Unknown session.serialize_handler. Failed to decode session object in %s on line %d -bool(true) +bool(false) array(3) { ["foo"]=> int(1234567890) diff --git a/ext/standard/tests/serialize/bug70219.phpt b/ext/standard/tests/serialize/bug70219.phpt new file mode 100644 index 0000000000..84a059f365 --- /dev/null +++ b/ext/standard/tests/serialize/bug70219.phpt @@ -0,0 +1,38 @@ +--TEST-- +Bug #70219 Use after free vulnerability in session deserializer +--FILE-- +data); + } + function unserialize($data) { + session_start(); + session_decode($data); + } +} + +$inner = 'ryat|a:1:{i:0;a:1:{i:1;'; +$exploit = 'a:2:{i:0;C:3:"obj":'.strlen($inner).':{'.$inner.'}i:1;R:4;}'; + +$data = unserialize($exploit); + +for ($i = 0; $i < 5; $i++) { + $v[$i] = 'hi'.$i; +} + +var_dump($data); +?> +--EXPECTF-- +Warning: session_decode(): Failed to decode session object. Session has been destroyed in %s on line %d +array(2) { + [0]=> + object(obj)#%d (1) { + ["data"]=> + NULL + } + [1]=> + array(0) { + } +} diff --git a/ext/standard/var_unserializer.c b/ext/standard/var_unserializer.c index ee0cac4762..ffaf680c51 100644 --- a/ext/standard/var_unserializer.c +++ b/ext/standard/var_unserializer.c @@ -1,4 +1,4 @@ -/* Generated by re2c 0.13.7.5 on Tue Mar 17 13:14:30 2015 */ +/* Generated by re2c 0.13.7.5 on Sun Aug 23 19:50:03 2015 */ #line 1 "ext/standard/var_unserializer.re" /* +----------------------------------------------------------------------+ @@ -92,7 +92,13 @@ PHPAPI void var_push_dtor(php_unserialize_data_t *var_hashx, zval **rval) PHPAPI void var_push_dtor_no_addref(php_unserialize_data_t *var_hashx, zval **rval) { - var_entries *var_hash = (*var_hashx)->last_dtor; + var_entries *var_hash; + + if (!var_hashx || !*var_hashx) { + return; + } + + var_hash = (*var_hashx)->last_dtor; #if VAR_ENTRIES_DBG fprintf(stderr, "var_push_dtor_no_addref(%ld): %d (%d)\n", var_hash?var_hash->used_slots:-1L, Z_TYPE_PP(rval), Z_REFCOUNT_PP(rval)); #endif @@ -121,7 +127,7 @@ PHPAPI void var_replace(php_unserialize_data_t *var_hashx, zval *ozval, zval **n #if VAR_ENTRIES_DBG fprintf(stderr, "var_replace(%ld): %d\n", var_hash?var_hash->used_slots:-1L, Z_TYPE_PP(nzval)); #endif - + while (var_hash) { for (i = 0; i < var_hash->used_slots; i++) { if (var_hash->data[i] == ozval) { @@ -139,7 +145,7 @@ static int var_access(php_unserialize_data_t *var_hashx, long id, zval ***store) #if VAR_ENTRIES_DBG fprintf(stderr, "var_access(%ld): %ld\n", var_hash?var_hash->used_slots:-1L, id); #endif - + while (id >= VAR_ENTRIES_MAX && var_hash && var_hash->used_slots == VAR_ENTRIES_MAX) { var_hash = var_hash->next; id -= VAR_ENTRIES_MAX; @@ -162,7 +168,7 @@ PHPAPI void var_destroy(php_unserialize_data_t *var_hashx) #if VAR_ENTRIES_DBG fprintf(stderr, "var_destroy(%ld)\n", var_hash?var_hash->used_slots:-1L); #endif - + while (var_hash) { next = var_hash->next; efree(var_hash); @@ -170,7 +176,7 @@ PHPAPI void var_destroy(php_unserialize_data_t *var_hashx) } var_hash = (*var_hashx)->first_dtor; - + while (var_hash) { for (i = 0; i < var_hash->used_slots; i++) { zval_ptr_dtor(&var_hash->data[i]); @@ -233,7 +239,7 @@ static char *unserialize_str(const unsigned char **p, size_t *len, size_t maxlen #define YYMARKER marker -#line 241 "ext/standard/var_unserializer.re" +#line 247 "ext/standard/var_unserializer.re" @@ -251,7 +257,7 @@ static inline long parse_iv2(const unsigned char *p, const unsigned char **q) case '+': p++; } - + while (1) { cursor = (char)*p; if (cursor >= '0' && cursor <= '9') { @@ -280,7 +286,7 @@ static inline size_t parse_uiv(const unsigned char *p) if (*p == '+') { p++; } - + while (1) { cursor = *p; if (cursor >= '0' && cursor <= '9') { @@ -304,24 +310,20 @@ static inline int process_nested_data(UNSERIALIZE_PARAMETER, HashTable *ht, long ALLOC_INIT_ZVAL(key); if (!php_var_unserialize(&key, p, max, NULL TSRMLS_CC)) { - zval_dtor(key); - FREE_ZVAL(key); + var_push_dtor_no_addref(var_hash, &key); return 0; } if (Z_TYPE_P(key) != IS_LONG && Z_TYPE_P(key) != IS_STRING) { - zval_dtor(key); - FREE_ZVAL(key); + var_push_dtor_no_addref(var_hash, &key); return 0; } ALLOC_INIT_ZVAL(data); if (!php_var_unserialize(&data, p, max, var_hash TSRMLS_CC)) { - zval_dtor(key); - FREE_ZVAL(key); - zval_dtor(data); - FREE_ZVAL(data); + var_push_dtor_no_addref(var_hash, &key); + var_push_dtor_no_addref(var_hash, &data); return 0; } @@ -350,9 +352,7 @@ static inline int process_nested_data(UNSERIALIZE_PARAMETER, HashTable *ht, long sizeof data, NULL); } var_push_dtor(var_hash, &data); - - zval_dtor(key); - FREE_ZVAL(key); + var_push_dtor_no_addref(var_hash, &key); if (elements && *(*p-1) != ';' && *(*p-1) != '}') { (*p)--; @@ -402,11 +402,11 @@ static inline int object_custom(UNSERIALIZE_PARAMETER, zend_class_entry *ce) static inline long object_common1(UNSERIALIZE_PARAMETER, zend_class_entry *ce) { long elements; - + elements = parse_iv2((*p) + 2, p); (*p) += 2; - + /* The internal class check here is a BC fix only, userspace classes implementing the Serializable interface have eventually an inconsistent behavior at this place when unserialized from a manipulated string. Additionaly the interal classes can possibly @@ -470,19 +470,19 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) limit = max; cursor = *p; - + if (YYCURSOR >= YYLIMIT) { return 0; } - + if (var_hash && cursor[0] != 'R') { var_push(var_hash, rval); } start = cursor; - - + + #line 488 "ext/standard/var_unserializer.c" { @@ -645,7 +645,7 @@ yy20: if (*start == 'C') { custom_object = 1; } - + INIT_PZVAL(*rval); len2 = len = parse_uiv(start + 2); maxlen = max - YYCURSOR; @@ -694,14 +694,14 @@ yy20: efree(class_name); return 0; } - + /* Check for unserialize callback */ if ((PG(unserialize_callback_func) == NULL) || (PG(unserialize_callback_func)[0] == '\0')) { incomplete_class = 1; ce = PHP_IC_ENTRY; break; } - + /* Call unserialize callback */ MAKE_STD_ZVAL(user_func); ZVAL_STRING(user_func, PG(unserialize_callback_func), 1); @@ -734,7 +734,7 @@ yy20: zval_ptr_dtor(&arg_func_name); return 0; } - + /* The callback function may have defined the class */ if (zend_lookup_class(class_name, len2, &pce TSRMLS_CC) == SUCCESS) { ce = *pce; @@ -762,7 +762,7 @@ yy20: efree(class_name); return ret; } - + elements = object_common1(UNSERIALIZE_PASSTHRU, ce); if (incomplete_class) { @@ -801,7 +801,7 @@ yy27: { INIT_PZVAL(*rval); - + return object_common2(UNSERIALIZE_PASSTHRU, object_common1(UNSERIALIZE_PASSTHRU, ZEND_STANDARD_CLASS_DEF_PTR)); } @@ -1239,7 +1239,7 @@ yy91: *rval = *rval_ref; Z_ADDREF_PP(rval); Z_UNSET_ISREF_PP(rval); - + return 1; } #line 1246 "ext/standard/var_unserializer.c" @@ -1283,7 +1283,7 @@ yy97: *rval = *rval_ref; Z_ADDREF_PP(rval); Z_SET_ISREF_PP(rval); - + return 1; } #line 1290 "ext/standard/var_unserializer.c" diff --git a/ext/standard/var_unserializer.re b/ext/standard/var_unserializer.re index abac77ccea..f02602cd7e 100644 --- a/ext/standard/var_unserializer.re +++ b/ext/standard/var_unserializer.re @@ -90,7 +90,13 @@ PHPAPI void var_push_dtor(php_unserialize_data_t *var_hashx, zval **rval) PHPAPI void var_push_dtor_no_addref(php_unserialize_data_t *var_hashx, zval **rval) { - var_entries *var_hash = (*var_hashx)->last_dtor; + var_entries *var_hash; + + if (!var_hashx || !*var_hashx) { + return; + } + + var_hash = (*var_hashx)->last_dtor; #if VAR_ENTRIES_DBG fprintf(stderr, "var_push_dtor_no_addref(%ld): %d (%d)\n", var_hash?var_hash->used_slots:-1L, Z_TYPE_PP(rval), Z_REFCOUNT_PP(rval)); #endif @@ -119,7 +125,7 @@ PHPAPI void var_replace(php_unserialize_data_t *var_hashx, zval *ozval, zval **n #if VAR_ENTRIES_DBG fprintf(stderr, "var_replace(%ld): %d\n", var_hash?var_hash->used_slots:-1L, Z_TYPE_PP(nzval)); #endif - + while (var_hash) { for (i = 0; i < var_hash->used_slots; i++) { if (var_hash->data[i] == ozval) { @@ -137,7 +143,7 @@ static int var_access(php_unserialize_data_t *var_hashx, long id, zval ***store) #if VAR_ENTRIES_DBG fprintf(stderr, "var_access(%ld): %ld\n", var_hash?var_hash->used_slots:-1L, id); #endif - + while (id >= VAR_ENTRIES_MAX && var_hash && var_hash->used_slots == VAR_ENTRIES_MAX) { var_hash = var_hash->next; id -= VAR_ENTRIES_MAX; @@ -160,7 +166,7 @@ PHPAPI void var_destroy(php_unserialize_data_t *var_hashx) #if VAR_ENTRIES_DBG fprintf(stderr, "var_destroy(%ld)\n", var_hash?var_hash->used_slots:-1L); #endif - + while (var_hash) { next = var_hash->next; efree(var_hash); @@ -168,7 +174,7 @@ PHPAPI void var_destroy(php_unserialize_data_t *var_hashx) } var_hash = (*var_hashx)->first_dtor; - + while (var_hash) { for (i = 0; i < var_hash->used_slots; i++) { zval_ptr_dtor(&var_hash->data[i]); @@ -255,7 +261,7 @@ static inline long parse_iv2(const unsigned char *p, const unsigned char **q) case '+': p++; } - + while (1) { cursor = (char)*p; if (cursor >= '0' && cursor <= '9') { @@ -284,7 +290,7 @@ static inline size_t parse_uiv(const unsigned char *p) if (*p == '+') { p++; } - + while (1) { cursor = *p; if (cursor >= '0' && cursor <= '9') { @@ -308,24 +314,20 @@ static inline int process_nested_data(UNSERIALIZE_PARAMETER, HashTable *ht, long ALLOC_INIT_ZVAL(key); if (!php_var_unserialize(&key, p, max, NULL TSRMLS_CC)) { - zval_dtor(key); - FREE_ZVAL(key); + var_push_dtor_no_addref(var_hash, &key); return 0; } if (Z_TYPE_P(key) != IS_LONG && Z_TYPE_P(key) != IS_STRING) { - zval_dtor(key); - FREE_ZVAL(key); + var_push_dtor_no_addref(var_hash, &key); return 0; } ALLOC_INIT_ZVAL(data); if (!php_var_unserialize(&data, p, max, var_hash TSRMLS_CC)) { - zval_dtor(key); - FREE_ZVAL(key); - zval_dtor(data); - FREE_ZVAL(data); + var_push_dtor_no_addref(var_hash, &key); + var_push_dtor_no_addref(var_hash, &data); return 0; } @@ -354,9 +356,7 @@ static inline int process_nested_data(UNSERIALIZE_PARAMETER, HashTable *ht, long sizeof data, NULL); } var_push_dtor(var_hash, &data); - - zval_dtor(key); - FREE_ZVAL(key); + var_push_dtor_no_addref(var_hash, &key); if (elements && *(*p-1) != ';' && *(*p-1) != '}') { (*p)--; @@ -406,11 +406,11 @@ static inline int object_custom(UNSERIALIZE_PARAMETER, zend_class_entry *ce) static inline long object_common1(UNSERIALIZE_PARAMETER, zend_class_entry *ce) { long elements; - + elements = parse_iv2((*p) + 2, p); (*p) += 2; - + /* The internal class check here is a BC fix only, userspace classes implementing the Serializable interface have eventually an inconsistent behavior at this place when unserialized from a manipulated string. Additionaly the interal classes can possibly @@ -474,19 +474,19 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) limit = max; cursor = *p; - + if (YYCURSOR >= YYLIMIT) { return 0; } - + if (var_hash && cursor[0] != 'R') { var_push(var_hash, rval); } start = cursor; - - + + /*!re2c "R:" iv ";" { @@ -506,7 +506,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) *rval = *rval_ref; Z_ADDREF_PP(rval); Z_SET_ISREF_PP(rval); - + return 1; } @@ -529,7 +529,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) *rval = *rval_ref; Z_ADDREF_PP(rval); Z_UNSET_ISREF_PP(rval); - + return 1; } @@ -679,7 +679,7 @@ use_double: "o:" iv ":" ["] { INIT_PZVAL(*rval); - + return object_common2(UNSERIALIZE_PASSTHRU, object_common1(UNSERIALIZE_PASSTHRU, ZEND_STANDARD_CLASS_DEF_PTR)); } @@ -702,7 +702,7 @@ object ":" uiv ":" ["] { if (*start == 'C') { custom_object = 1; } - + INIT_PZVAL(*rval); len2 = len = parse_uiv(start + 2); maxlen = max - YYCURSOR; @@ -751,14 +751,14 @@ object ":" uiv ":" ["] { efree(class_name); return 0; } - + /* Check for unserialize callback */ if ((PG(unserialize_callback_func) == NULL) || (PG(unserialize_callback_func)[0] == '\0')) { incomplete_class = 1; ce = PHP_IC_ENTRY; break; } - + /* Call unserialize callback */ MAKE_STD_ZVAL(user_func); ZVAL_STRING(user_func, PG(unserialize_callback_func), 1); @@ -791,7 +791,7 @@ object ":" uiv ":" ["] { zval_ptr_dtor(&arg_func_name); return 0; } - + /* The callback function may have defined the class */ if (zend_lookup_class(class_name, len2, &pce TSRMLS_CC) == SUCCESS) { ce = *pce; @@ -819,7 +819,7 @@ object ":" uiv ":" ["] { efree(class_name); return ret; } - + elements = object_common1(UNSERIALIZE_PASSTHRU, ce); if (incomplete_class) { -- cgit v1.2.1